BgImageA PictureEditor.com tool

Why gradients band, and what to do about it

The stripes across a smooth ramp are not a rendering mistake. They are the arithmetic of eight bits meeting a frame that is wider than the number of values eight bits can hold.

256 levels, and a frame that needs more

A channel in an ordinary image file holds one byte, which is 256 possible values. A ramp from a dark tone to a light one does not use all of them — it uses the span between its two ends. A ramp covering half the range has about 128 levels to work with.

Spread those 128 levels across 1920 pixels and each one has to be held for fifteen pixels before the next is allowed. Fifteen pixels of identical colour with a hard step at the end of it is a stripe, and the eye is extraordinarily good at finding stripes: lateral inhibition in the retina exaggerates exactly this kind of edge, which is why a step of one 255th is visible at all.

How wide each step gets, for a ramp crossing half the range
Ramp runs acrossPixels per levelVisible?
400 px3rarely
1080 px8on a flat area
1920 px15usually
3840 px30always

What a dither pass trades

Dithering does not add levels. Nothing can: the file holds bytes and a byte has 256 values. What it does is decide, per pixel, whether to round up or down in a way that is not the same for every pixel on the same side of a boundary.

The mechanism, precisely

Before each value is rounded, a small perturbation is added to it — here, a triangular distribution about one level wide, derived from a hash of the pixel’s coordinates so that the same design always produces the same grain. A pixel that was going to round down to 119 now rounds to 119 or 120 depending on where in the level it sat and what the perturbation was. The straight edge becomes a scatter, and the average across any small area is closer to the true value than the undithered version was.

The trade is real and worth stating plainly. The banding goes; grain arrives. On a screen at normal viewing distance the grain is invisible and the banding was not, which is why the pass is on by default. In a file it is anything but free: a compressor that was storing two thousand identical pixels as a run now has two thousand slightly different ones, and a flat-ish PNG can grow by an order of magnitude.

Roughly what the pass costs a 1920 × 1080 ramp
DesignDither offDither on
Two-stop ramp, PNGtens of kilobytesaround a megabyte
Two-stop ramp, WebPtens of kilobytesa few hundred kilobytes
Flat colour, PNGa few kilobytesa few kilobytes

The last row is why the flat presets in the library ship with it switched off. A single colour has no boundary to hide, so the pass would add weight and grain in exchange for nothing at all.

The other three ways to make a step narrower

Dither is the general answer. Three specific ones are worth knowing, because each removes the problem rather than trading it.

Shorten the ramp. The same two colours across 600 pixels instead of 1920 gives each level a third of the distance to cover. A radial gradient does this naturally in a rectangular frame — the falloff is steepest in the short direction.

Angle it. A ramp at 0 or 90 degrees puts its steps parallel to the edges of the frame, which is exactly where the eye is already looking for straight lines. Run it at 140 degrees and the same steps cross the frame diagonally and are considerably harder to see.

Put something on top. A noise layer at four or five per cent over the whole design does what the dither pass does, only louder and as a visible surface rather than an invisible correction. It is the difference between hiding an artefact and deciding on a texture.

Questions about banding

Is banding a fault in the file or in my screen?
Usually the file, sometimes both. An eight-bit file genuinely contains the steps, and a good screen shows them faithfully. A screen can add its own on top: a panel doing six bits with temporal dithering, or a display pipeline converting colour spaces on the fly, will introduce steps that are not in the file at all. The test is to open the same file on another screen — if the stripes move, they are the display's.
Does saving as PNG instead of JPG fix it?
No. PNG is lossless, so it preserves the banding exactly; JPG's block transform sometimes smears a step slightly and can look marginally better by accident, at the cost of ringing everywhere else. Neither format adds levels that were not in the pixels. The fix has to happen while the image is being drawn, which is where the dither pass sits.
What does the dither control actually add?
About one level of noise, shaped so that the error either side of a step is spread rather than aligned. Each pixel gets a small triangular perturbation before the value is rounded to a whole byte, so the boundary between two levels becomes a soft scatter rather than a straight edge. It is deterministic — the same design produces the same grain every time — and it costs file size, because a compressor can no longer find the runs of identical pixels it was relying on.
Would a sixteen-bit intermediate help?
Only where the output is not eight bits. The renderer here already works in floating point and quantises once, at the end, so there is no precision being thrown away part-way through a chain. When the last step is still a byte per channel, a wider intermediate changes nothing you can see. Where it does matter is a pipeline with several eight-bit stages in it, each rounding again — that compounds, and a single-pass renderer avoids it by construction.

Back to the canvas

Nothing here is sent anywhere. The file is drawn by your browser and written to your disk.