Everyone has seen it. You take a clean screenshot of an application, send it to a colleague, and what arrives has faint grey fuzz around every letter, smeared colour on the syntax highlighting, and a general sense that someone photographed the monitor rather than captured it.
The file is a JPG, and nothing went wrong. The encoder did exactly what it was designed to do. It was just designed for a completely different kind of picture.
JPEG was built for photographs, and it shows
JPEG’s compression rests on an assumption about its input: that brightness changes gradually across the frame. It divides the image into blocks of 8 by 8 pixels and describes each block not as sixty-four separate values but as a sum of wave patterns, from a flat block-wide average up through progressively finer ripples. Most of a photograph’s energy lands in the coarse patterns, because skin, sky, foliage and fabric genuinely do vary smoothly. The fine ripples carry very little, so the encoder stores them crudely or not at all, and the eye never misses them.
That assumption holds beautifully for a photograph and collapses for a screenshot.
A hard black-on-white edge, which is what the side of every letter and every window border is, is the exact opposite of a gradual change. Reconstructing a perfect step out of smooth waves requires an enormous number of fine ones, all present and all accurate. Quantisation removes precisely those. What comes back is the same step approximated by too few waves, which overshoots on one side and undershoots on the other. That overshoot is the grey halo you can see hugging the text, and it has a name in signal processing that predates JPEG by a century: ringing.
The blocks give it a second signature. Because each 8 by 8 block is quantised independently, the error does not blend across block boundaries, so a long horizontal rule or a table border can pick up a faint dashed quality where one block guessed slightly differently from its neighbour.
Colour gets halved before compression even begins
There is a second mechanism, and it is the one that ruins syntax highlighting specifically.
Human vision resolves brightness far more sharply than colour, so JPEG encoders routinely store the colour channels at half resolution horizontally and vertically, keeping full detail only for luminance. On a photograph this is nearly free. On a screenshot it means the colour information for a one-pixel-wide red keyword is being reconstructed from a grid with half the resolution of the text itself.
The result is the smeared, slightly wrong colour along coloured text that no amount of squinting resolves. The letters are still sharp in brightness, because luminance kept its full resolution, but the colour has bled sideways into the background. It is why a screenshot of code is one of the worst possible things to hand a JPEG encoder, and why Code Screenshot exists as a separate tool that renders the code directly rather than asking you to capture and compress it.
The counterintuitive part: PNG is usually smaller too
The instinct is to accept some damage in exchange for a smaller file. For screenshots that trade often does not exist, because PNG is not competing on the same terms.
PNG compression is lossless and works by finding structure: runs of identical pixels, rows that resemble the row above, a limited total number of distinct colours. A screenshot is close to the ideal input. Enormous areas are a single flat colour, the interface repeats itself, and a typical application window might contain a few thousand distinct colours rather than the hundreds of thousands in a photograph.
JPEG cannot exploit any of that. It has no representation for “this block is exactly the same as the last four hundred blocks”. It spends bits describing each of them approximately.
So on an ordinary interface screenshot you frequently get a PNG that is both smaller and exact. The trade you thought you were making, quality for size, turns out to cost you quality and give you nothing.
Making a screenshot smaller without ruining it
If a PNG screenshot really is too large, there are two honest levers and one false one.
The first is optimisation. Optimize PNG runs oxipng over the file, trying different filter and compression strategies to find a smaller encoding of the identical pixels. It is lossless by construction, and it compares its own output against your original and hands back whichever is smaller, so it can never make a file bigger. Effort levels run from 0 to 6, with 2 as the balanced default.
The second is dimensions. Half the width and half the height is a quarter of the pixels, and for a screenshot that only needs to be legible in a document rather than pixel-exact, that is usually where the real saving lives.
The false lever is a quality slider. Compress Images deliberately keeps the input format, so a PNG stays a PNG, and the browser’s PNG encoder is lossless and ignores a quality value entirely. Its quality number does nothing at all on a PNG; only its downscaling option changes anything. That is a deliberate design choice rather than an oversight, because silently converting your screenshot to JPEG to hit a size target would produce exactly the artefacts this article is about.
When JPEG is the right answer
The rule is about content, not about where the file came from.
If your screenshot is mostly a photograph, a captured video frame, a photo editor with a large image open, a game, then it behaves like a photograph and JPEG will serve it well and compactly. If it is an interface, text, a chart, a diagram or a code listing, it behaves like line art and belongs in PNG.
When you do need to convert, PNG to JPG defaults to quality 0.9, which is high enough that ringing stays subtle on most content. It also asks you for a background colour, defaulting to white, and that question is not cosmetic: JPEG has no alpha channel at all, so any transparency in the source has to become some actual colour. A screenshot with rounded transparent corners will come back with those corners filled in.
Going the other way, JPG to PNG is worth understanding correctly. It cannot undo compression, and any halo already baked into the pixels stays. What it does is stop the bleeding, which matters if you are about to annotate, crop or re-save the image several times over, since each JPEG generation compounds the last one’s artefacts.
The short version
Screenshots are line art wearing the clothes of a photograph. They are full of the two things JPEG handles worst, hard edges and flat colour, and empty of the smooth gradients it handles best. Save them as PNG, optimise losslessly if the size matters, reduce the dimensions if that is not enough, and reach for JPEG only when what is on the screen is genuinely a photograph.

