Skip to content
Spellkit

Why JPEG Artifacts Look the Way They Do

Blocking, ringing, and color smearing aren't random damage. Each one is a direct fingerprint of a specific step in how JPEG throws information away.

Over-compressed JPEGs fail in a very particular way. You get 8-pixel squares along smooth gradients, shimmering fuzz hugging sharp edges, and colors that bleed past the shapes they belong to. These aren't three kinds of damage — they're three steps of the same algorithm, each leaving its own signature. Knowing which artifact you're looking at tells you what to change.

Step one: separating brightness from color

JPEG's first move is to convert RGB into YCbCr: one channel for luma (Y, brightness) and two for chroma (Cb and Cr, blue-difference and red-difference). This isn't compression yet, just a change of coordinates. It matters because human vision has far more spatial acuity for brightness than for color — we can resolve fine light-dark detail that we simply cannot resolve in hue.

So JPEG exploits that with chroma subsampling. In the common 4:2:0 mode, the two color channels are stored at half resolution in both directions, throwing away three quarters of the color samples before anything else happens. Luma stays full resolution. For photographs this is nearly free: you've cut the data substantially and most people can't see a difference.

For anything with saturated, hard-edged color it's very much not free. Red text on white, a thin cyan line, a logo with a crisp color boundary — these have real detail in the chroma channels, and half-resolution chroma smears it. That's the color bleeding you see around colored text in a compressed screenshot: the edge is sharp in luma and blurry in chroma, so the color spills roughly a pixel or two past where the shape ends.

This is the first and best explanation for why screenshots of text should not be JPEGs. Convert them to PNG instead — a lossless format has no chroma channel to subsample.

Step two: the 8×8 blocks

Each channel is then chopped into 8×8 pixel blocks, and each block is transformed independently by a discrete cosine transform. The DCT doesn't compress anything by itself; it's a lossless change of representation. It takes the 64 pixel values and re-expresses them as 64 coefficients, each describing how much of a particular 2D cosine wave pattern is present — from the flat "average brightness of this block" term in the corner, through gentle gradients, up to the finest possible checkerboard.

The point of this rearrangement is that natural images are dominated by low frequencies. Most 8×8 patches of a photograph are close to a smooth gradient, so after the DCT nearly all the energy piles into a handful of coefficients near the low-frequency corner and the high-frequency coefficients are already close to zero.

That the blocks are transformed independently is the crucial detail. Nothing in the math forces neighboring blocks to agree at their shared border.

Step three: quantization, where the loss happens

Now the actual compression. Each of the 64 coefficients is divided by a corresponding entry in a quantization table and rounded to an integer. The table has small divisors for low frequencies and large ones for high frequencies, encoding the assumption that fine detail matters less perceptually than overall shape.

The quality slider is nothing more than a scale factor on that table. Quality 90 multiplies the divisors by a small number; quality 30 multiplies them by a large one. At high divisors, most high-frequency coefficients round to zero and disappear entirely. Everything after this — zigzag ordering, run-length coding, Huffman entropy coding — is lossless packing of whatever survived.

Two artifacts follow directly:

Blocking. Because each block is quantized on its own, adjacent blocks in a smooth gradient can round their average-brightness terms to slightly different values. In the original the transition was continuous; now there's a small step at every 8-pixel boundary. Across a clear sky or a soft shadow, those steps line up into a visible grid. Blocking is the signature of the DC term being quantized too coarsely.

Ringing (mosquito noise). A sharp edge is, in frequency terms, a sum of many high-frequency components in careful balance. Quantization coarsens some and deletes others, and the reconstruction of that broken sum overshoots and undershoots around the edge — the same Gibbs phenomenon that makes a truncated Fourier series wobble near a discontinuity. You see it as faint light and dark ripples parallel to hard edges, most obvious around text and line art on a flat background. Ringing is the signature of high-frequency coefficients being destroyed.

So the artifact tells you the cause. Grid squares in smooth areas means the quality setting is too low for the gradients present. Shimmer around edges means the image has hard edges that JPEG is structurally bad at. Color smearing at colored edges means chroma subsampling is the problem, not quality.

Why quality 100 still isn't lossless

At quality 100 the quantization divisors are mostly 1, so almost nothing is discarded there. But the color space conversion involves rounding, the DCT is computed in finite precision, and many encoders still subsample chroma unless explicitly told not to. JPEG has no lossless mode in ordinary use. Quality 100 is merely very-nearly-lossless, at a file size often several times larger than quality 90 for a difference nobody can see.

Why re-saving keeps degrading it

Each save runs the whole pipeline again. Decoding produces pixel values that are close to but not exactly on the quantization grid, so re-encoding rounds them again — to different values. Detail is lost, then the artifacts introduced by that loss are themselves treated as image content and encoded, and their own artifacts compound. This is generation loss, and it's why an image that has been through a group chat a few times looks the way it does.

The exception: if you re-save at the exact same quality with the same encoder and identical settings, the values are already on the grid and the result is nearly stable. That's fragile and not worth relying on. The reliable rule is to keep an original and export from it every time, never edit-and-resave the export.

Practical consequences

  • Photographs: JPEG is genuinely good. Quality 75–85 is the usual sweet spot; above 90 you're mostly paying for bytes nobody can perceive.
  • Text, screenshots, line art, logos: use PNG. Every JPEG failure mode is triggered by exactly the hard edges and flat saturated colors these contain.
  • Images with transparency: JPEG has no alpha channel at all. Transparent pixels get flattened, usually onto black or white.
  • Reduce dimensions before reducing quality. Fewer pixels means less high-frequency content per block for the quantizer to mangle. When you need to hit a specific file size, shrinking first and compressing gently almost always looks better than keeping full dimensions and crushing quality.

JPEG has survived for three decades because its assumptions — that brightness matters more than color, and that natural images are mostly smooth — are true for photographs. Its artifacts are simply what those assumptions look like when the content violates them.