Image compression is often treated as a black box with a quality slider on the front. It is not — the mechanisms are comprehensible without any mathematics, and understanding them tells you immediately why JPEG destroys screenshots, why PNG is enormous for photographs, and what you are actually giving up when you move that slider.
The two families
Lossless compression finds exact repetition and encodes it more briefly. Nothing is discarded, and the original is reconstructed perfectly. Lossy compression discards information the eye is bad at noticing, which allows far greater savings and cannot be undone. PNG is the first; JPEG, WebP and AVIF are the second.
Lossless: finding repetition
Lossless compression rests on one observation: real data contains patterns, and patterns can be described more briefly than they can be listed.
PNG uses something more sophisticated — DEFLATE, the same algorithm inside ZIP — which combines two techniques. LZ77 replaces repeated sequences with a reference back to where they last appeared, and Huffman coding assigns shorter bit patterns to more frequent values.
The prediction filters
PNG's genuinely clever step happens before compression. Each row of pixels is filtered: rather than storing pixel values, PNG stores the difference between each pixel and a prediction based on its neighbours.
| Filter | Predicts each pixel from | Suits |
|---|---|---|
| None | Nothing | Already random data |
| Sub | The pixel to the left | Horizontal gradients |
| Up | The pixel above | Vertical gradients |
| Average | Mean of left and above | Smooth areas |
| Paeth | Left, above, or above-left | Most photographic content |
Why this helps: a smooth gradient stored as raw values is a long list of different numbers. Stored as differences it becomes a long run of the same small number — and runs of identical values are exactly what DEFLATE compresses well. The filter does not compress anything itself; it rearranges the data into a form that compresses.
A good encoder tries every filter on every row and keeps whichever produces the most compressible output. This is why PNG optimisers such as oxipng and zopflipng can shrink a file by 20% without changing a single pixel — they simply search harder for the best filter choices.
💡 Why PNG fails on photographs
Lossless compression needs exact repetition. A photograph has almost none: sensor noise means two visually identical patches of sky have slightly different values in every pixel. There is nothing to collapse, so PNG stores essentially everything.
A screenshot is the opposite — thousands of pixels of precisely the same toolbar grey — which is why PNG often beats JPEG on interface images in both size and quality.
Lossy: discarding what the eye ignores
Lossy compression exploits the fact that human vision is not a uniform sensor. It is far more sensitive to some information than to others, and the parts it barely registers can be thrown away almost for free.
Three facts about vision do most of the work:
- Brightness matters more than colour. We have roughly twenty times more rod cells, which detect luminance, than the cone cells that detect colour.
- Gradual change matters more than fine detail. The overall shape of a face registers strongly; the exact texture of one square millimetre of skin does not.
- Context masks error. A small error next to a strong edge is invisible; the same error in a flat area is obvious.
How JPEG works, step by step
1. Separate brightness from colour
The image is converted from RGB into YCbCr — Y for luminance, Cb and Cr for the two colour difference channels. This separates the information we are sensitive to from the information we are not.
2. Throw away most of the colour
Because colour resolution matters so little, JPEG simply stores less of it. This is chroma subsampling:
| Notation | Colour resolution | Data saved | Use for |
|---|---|---|---|
4:4:4 | Full | None | Text, screenshots, editing masters |
4:2:2 | Half horizontally | 33% | Video, broadcast |
4:2:0 | Half both ways | 50% | Photographs — the default |
At 4:2:0, three quarters of the colour information is discarded before any compression happens, and on a photograph you cannot see it. On red text against a white background you absolutely can — the edges become soft and fringed, because the sharp colour boundary is being stored at half resolution in both directions. This is the specific reason red text looks terrible in JPEG.
3. Split into 8×8 blocks and transform
Each channel is divided into 8×8 pixel blocks, and each block is put through a discrete cosine transform. This is the conceptual heart of JPEG, and the intuition is simpler than the name suggests.
The DCT re-describes the block. Instead of 64 pixel values, you get 64 numbers describing how much of each pattern the block contains — from "flat average brightness" through gentle gradients up to fine alternating detail.
Nothing has been lost yet — the transform is exactly reversible. What it has done is concentrate the important information into the first few numbers, so that discarding the rest costs little.
4. Quantisation — the actual lossy step
Each of the 64 coefficients is divided by a value from a quantisation table and rounded to a whole number. The divisors are small for the coefficients we care about and large for the ones we do not.
This is what the quality slider controls. It scales the entire quantisation table. Quality 90 uses small divisors, so few coefficients round to zero. Quality 40 uses large ones, so most of them do.
The scaling is not linear, which explains a familiar frustration: the difference between 95 and 100 is nearly invisible while the file grows substantially, and the difference between 50 and 40 is dramatic. For photographs, quality 80–85 is the point of diminishing returns — above it you pay in bytes for detail nobody sees.
5. Reorder and entropy-code
The 64 coefficients are read in a zigzag from the low-frequency corner, which groups all the zeros together at the end. A run of forty zeros is then encoded in a few bits, and Huffman coding compresses the rest.
⚠️ Why the artefacts look the way they do
Blocking — visible 8×8 squares in smooth gradients, because each block was quantised independently and they no longer join smoothly.
Ringing — ripples radiating from sharp edges. An abrupt edge requires all the high-frequency coefficients to reproduce; discard them and you get the wave-like remainder. This is the same phenomenon as Gibbs ringing in signal processing.
Colour bleeding — colour spilling across boundaries, from chroma subsampling.
All three are direct, predictable consequences of the steps above rather than flaws in an implementation.
What WebP and AVIF do differently
Modern formats keep the same overall structure — transform, quantise, entropy-code — and improve every stage.
| Improvement | JPEG | WebP / AVIF |
|---|---|---|
| Block size | Fixed 8×8 | Variable, 4×4 to 128×128 |
| Prediction | None between blocks | Predicts each block from its neighbours |
| Transform | DCT only | DCT plus alternatives per block |
| Entropy coding | Huffman | Arithmetic / range coding |
| Deblocking | None | Built-in filter |
| Transparency | None | Full alpha channel |
The two biggest wins are prediction and variable block size. Prediction means a block is encoded as the difference from what the neighbouring blocks suggest it should be — and differences are small, so they compress well. JPEG treats every block as if it appeared from nowhere.
Variable block size lets a large flat area of sky be one 128×128 block described very briefly, while a detailed region uses many small blocks. JPEG spends the same effort on both.
| Format | Size vs JPEG | Encode speed | Support |
|---|---|---|---|
| JPEG | Baseline | Very fast | Universal |
| MozJPEG | ~10% smaller | Fast | Universal (still JPEG) |
| WebP | ~25–35% smaller | Fast | All modern browsers |
| AVIF | ~50% smaller | Slow | All modern browsers |
| JPEG XL | ~50% smaller | Moderate | Limited |
✅ MozJPEG is free improvement
MozJPEG produces files roughly 10% smaller than a standard encoder while remaining completely ordinary JPEG — every decoder reads it. It achieves this with better quantisation tables and trellis optimisation, which searches for coefficient choices that compress better at the same visual quality. No compatibility cost, no format migration, just a better encoder.
Generational loss
Each JPEG save quantises again. Because decoding does not reproduce the original values exactly, the second encode is working on already-degraded data, and its errors add to the first set.
Two clarifications worth making. Opening and viewing a JPEG changes nothing — only re-encoding causes loss. And re-saving at the same quality with the same encoder and no edits is nearly lossless, because the coefficients are already quantised to that table's grid. It is editing, resizing or changing quality between saves that causes the damage.
The practical rule: keep the original in a lossless format, edit that, and export to JPEG once at the end.
Choosing a format
| Content | Best choice | Why |
|---|---|---|
| Photographs on the web | AVIF, WebP fallback | Lossy suits continuous tone |
| Screenshots, interfaces | PNG | Flat colour compresses losslessly; no ringing on text |
| Logos, icons, diagrams | SVG | Vector — resolution-independent and tiny |
| Needs transparency | PNG, WebP, AVIF | JPEG has no alpha channel |
| Editing master | TIFF, PSD, or raw | No generational loss |
| Maximum compatibility | JPEG (MozJPEG) | Everything reads it |
| Animation | WebP, AVIF, or video | GIF is 256 colours and very inefficient |
Compress an image and see the difference
Adjust quality and watch the file size change in real time — everything runs in your browser, so the original never leaves your device.
Open the Image Compressor →Summary
- Lossless finds exact repetition; lossy discards what the eye ignores.
- PNG filters rows into differences before compressing, which is why optimisers can shrink files without changing pixels.
- JPEG separates brightness from colour and throws away three quarters of the colour.
- The quality slider scales the quantisation table — how aggressively detail is rounded to zero.
- Ringing around text is inherent, not a bug: edges are pure high frequency, which is what JPEG discards.
- WebP and AVIF add prediction and variable block sizes, worth 25–50%.
- Generational loss comes from re-encoding, not from viewing.
- Quality 80–85 is the sensible ceiling for photographs.
Frequently Asked Questions
What does the JPEG quality slider actually change?
It scales the quantisation table — the set of divisors applied to the frequency coefficients of each 8x8 block. Higher quality means smaller divisors, so fewer coefficients round to zero and more detail survives. It is not a linear measure of quality, which is why the difference between 95 and 100 is barely visible while 50 to 40 is dramatic.
Why does JPEG make text look bad?
JPEG discards high-frequency information, and a letter's edge — an instant jump from black to white — is pure high frequency. Removing it leaves ringing artefacts that ripple outward from every edge. Photographs hide this because they contain little abrupt change; text is nothing but abrupt change.
Why is PNG so large for photographs?
PNG is lossless and compresses by finding exact repetition. A photograph has almost none — adjacent pixels differ slightly because of sensor noise and natural variation, so there is nothing to collapse. PNG excels at flat colour areas and screenshots, where long runs of identical pixels genuinely repeat.
Is WebP better than JPEG?
Usually, by roughly 25 to 35% at equal visual quality. It uses smarter prediction, a better transform and more efficient entropy coding, and it also supports transparency and animation, which JPEG cannot do at all. AVIF is better again but encodes considerably more slowly.
Does saving a JPEG repeatedly degrade it?
Yes. Each save quantises again, and because decoding never reproduces the original values exactly, each round loses a little more. Simply opening and viewing a file is harmless — only re-encoding causes loss. Keep an original in a lossless format and export from that.