Somebody sends you a photograph in a group chat. You save it, crop it, save it again, send it on, and somebody else does the same. By the time it reaches the page it is covered in square patches in the flat areas, coloured smearing along every hard edge, and a fizz of dots around any lettering. It is recognisably the same picture and it is unusable.
The instinct is to reach for sharpening, which makes it worse by amplifying exactly the artefacts you were trying to lose, or for noise reduction, which softens the whole picture in order to hide them. Neither is addressing what actually happened, because neither knows what actually happened.
What happened is specific and it is worth understanding, because the damage has a structure and structure is something a model can be taught.
The shape of JPEG damage
JPEG does not compress pixels. It cuts the picture into blocks of eight by eight pixels, converts each block into a set of frequency coefficients, and then throws away precision in the coefficients that carry fine detail. Reconstructing the block from what is left gives you something close to the original, and the error it makes is not random: it is a pattern that lives inside those eight by eight boundaries.
That is why heavy compression produces visible squares. Two neighbouring blocks each get their own approximation, the approximations do not quite meet at the boundary, and the eye is very good at seeing a straight line where two flat areas fail to match. It is also why the damage clusters around edges: a hard edge needs high frequency coefficients to describe it, those are the first ones to be crushed, and what comes back is a ripple running along the edge.
Colour gets treated worse than brightness. Most JPEG encoders store colour at half resolution in each direction, on the reasoning that the eye is less sensitive to colour detail, which is true and also the reason a red logo on a white background comes back with a pink halo. And every one of these losses compounds: each save decodes the previous approximation and approximates it again, which is why the fifth generation of a picture is so much worse than the first.
A model that knows the grid
The network in the tool below was trained specifically on compressed images, which means it has seen this damage several million times and has learned what tends to lie underneath it. It knows that a straight discontinuity every eight pixels is probably a block boundary and not a feature of the scene. A general purpose sharpener knows no such thing and treats that boundary as an edge to enhance.
It weighs about 9.8 MB. Drop a battered picture in, press the button once to fetch the model, and compare the magnified before and after. Everything happens in this browser tab: the picture is never uploaded, and the only thing that travels is the model, coming down from this site the first time you ask for it.
JPEG artefact repair
A picture that has been through a group chat, saved again, forwarded and saved again comes back with square blocks in the flat areas, coloured smearing along hard edges and a fizz of dots around lettering. This runs a small network over it that was trained on exactly that damage, so it knows the eight by eight grid JPEG works in and rebuilds inside it instead of softening everything in sight. The network is about 9.8 MB, fetched from this site only after you ask for it, alongside a 3.5 MB runtime shared with the other model tools here. Your picture is read in this browser tab, never uploaded, and there is nowhere for it to be uploaded to.
Two other tools on this blog stand next to it. The Generation loss simulator shows the damage being done, saving pass after saving pass. The Image quality curve measures what a given quality setting costs before you commit to it. This one is the third step, the attempt to take some of it back.
or press Enter to pick one. JPEG, PNG or WebP.
Sample picture, drawn and then deliberately wrecked in this browser.
The network only ever answers at four times the width and four times the height. The answer is then drawn back down to whichever size you picked here, and that is the whole trick: the mending happened in the large version, where a block edge is sixteen pixels across and there is room to reason about it, so shrinking it again keeps the mended edge and quietly discards the invented detail. Original size is the setting for a picture that has to go back on a page.
| What happened | Value |
|---|
What this deliberately cannot do. What the compression threw away is gone. The model writes a plausible replacement for it, not the original, and on lettering and thin lines you can usually see which is which: a letter comes back sharp and slightly the wrong shape. A picture that was never damaged does not get better from this, it only gets different, because the model has been taught that every input is broken and will treat a clean edge as one more thing to fix. It is not an enlarger either. The four times output is a by-product of how the network was built, and it carries no detail that was not already implied in the small version, so printing from it will disappoint you. And it has no idea what your picture is of, so where the damage is heavy it will invent something confident and wrong rather than leave a gap.
How it is worked out. The picture is cut into tiles of 128 pixels with 16 pixels of margin on each inner side. The margin is fed to the network so the pixels at a tile border have their surroundings, and is then thrown away, which is what stops a grid appearing in the result. Each tile is padded with a mirrored strip until both its edges are multiples of eight, because that is the block size the network was built around and it refuses anything else. Everything the network hands back is four times the size, so every destination coordinate is multiplied by four before the piece is put in place, and the mirrored overhang is cut off at the same time. Pictures longer than 1200 pixels on their long edge are drawn down to that first, because the four times answer for a full sized photograph does not fit in a browser tab. Comparable tools exist and several of them are good. The difference worth naming here is the mechanism: this one runs in the tab, and the only thing that travels is the model, in the other direction.
Use the magnifier, not the thumbnail
The tool shows the picture small and then shows a crop of it at four times, without smoothing, before and after. That is deliberate, because judging this kind of repair from a thumbnail is close to useless.
Scaled down, almost anything looks better: the shrinking itself averages the artefacts away, so a picture you have done nothing to will appear improved next to its own full sized version. Everything that matters here happens at the scale of an eight pixel block, and at thumbnail size an eight pixel block is a fraction of a screen pixel.
Move the magnifier onto the places where this kind of damage lives rather than onto the middle of the subject. A flat area of sky, where blocking shows up as patchwork. A hard edge between two very different colours, where the ripple lives. Any lettering at all, which is where both the damage and the model’s invention are easiest to see. If the repair holds up in those three places, it holds up.
Why it repairs at four times the size
The model only ever answers at four times the width and four times the height. That looks like an odd constraint for a repair tool and it turns out to be the mechanism rather than an inconvenience.
A block boundary in the original is a single hard step between two adjacent pixels. There is nowhere to put a repair: whatever the correct value is, it has to be one of two pixels. At four times the size that same boundary is sixteen pixels across, and the network has room to lay down a gradient, to bend an edge back into shape, to spread a correction over a distance instead of into a single pixel.
The answer is then drawn back down to whatever size you asked for. Shrinking it keeps the mended edge, because the mend is a real change in the shape of the transition, and quietly discards the detail the network invented, because invented detail does not survive being averaged down. You get the repair without the hallucination, which is a better trade than it sounds.
That is also why the size control does not re-run anything. The four times answer is kept, and switching between original size, twice and four times just redraws from it.
Tiles, margins, and a number that is not negotiable
A whole photograph cannot go through in one pass, because the answer is sixteen times the area of the input and a browser tab will not hold that for anything larger than a thumbnail. So the picture is cut into tiles of 128 pixels.
Tiles need margins. A network that looks at a neighbourhood gives the wrong answer for a pixel whose neighbourhood has been cut away, and if you write those wrong edge pixels into the result you get a faint grid, which is a particularly bitter failure in a tool whose entire job is removing a grid. Each tile is therefore fed with sixteen extra pixels of margin on every inner side, and those sixteen pixels are discarded before the tile is written out. In the four times answer that margin is sixty four pixels, and every destination coordinate has to be multiplied by four, which is the single most likely place for this kind of code to go quietly wrong.
The constraint that is not negotiable is that both edge lengths must be divisible by eight. Feed the model anything else and it does not degrade, it aborts, because internally it reshapes the data into a grid of eight by eight windows and the arithmetic does not come out. A 50 by 70 tile has to become 56 by 72 first, and the way to do that without inventing content is to mirror the existing pixels outwards and cut the overhang off afterwards.
50 wide -> 56 wide, columns 50 to 55 mirror columns 49 down to 44
70 high -> 72 high, rows 70 and 71 mirror rows 69 and 68
after the model, cut the overhang back off
The result comes back as PNG, deliberately
A repaired JPEG saved as a JPEG is a JPEG that has been through one more generation. Everything the model just undid gets partially redone on the way out, at whatever quality setting the encoder happened to use, and the file you download is measurably worse than the one you were looking at.
So the download is PNG. It is a larger file and that is the correct trade for an intermediate: the point of this step is to hand you something clean to work from, not something finished to publish. When you do come to publish it, choose the output quality deliberately at that point, with the measured curve rather than a remembered default, and pick the format that suits the picture rather than the one the last tool defaulted to.
When not to use it
There is a category of picture where running this is actively the wrong move, and it is worth naming before you reach for it out of habit.
A photograph that came off a camera and has been saved once at a decent quality has damage well below the level anybody will notice on a page. Running a repair over it means accepting a small reworking of every edge in exchange for fixing something nobody could see. The same is true of a screenshot of an interface, where the flat areas are genuinely flat and the text was genuinely sharp: the model will treat crisp lettering as damaged lettering and give you back something marginally rounder.
The tool is for pictures whose history you can see. If you have to hunt for the artefacts, there is nothing here for you.
What it deliberately cannot do
What the compression threw away is gone. The model writes a plausible replacement for it, not the original. On lettering and thin lines you can usually see which is which if you look: a letter comes back sharp and slightly the wrong shape, because the network reconstructed a letter rather than recovering yours.
A picture that was never damaged does not get better from this. It gets different. The network was taught that every input is broken, so it will treat a clean edge as one more thing to fix, and the result is subtly softer and subtly reworked for no gain.
It is not an enlarger either. The four times output is a by-product of how the network was built and it carries no detail that was not already implied in the small version, so printing from it will disappoint you. And it has no idea what your picture is of, so where the damage is heavy it will invent something confident and wrong rather than leave a gap.
Pictures longer than 1200 pixels on their long edge are drawn down to that first, because the four times answer for a full sized photograph does not fit in a browser tab.
Where it fits in a workflow
Comparable tools exist and several of them are good. The difference worth naming here is mechanical rather than qualitative: this one runs in the tab, and the only thing that travels is the model, in the other direction. For a picture somebody else sent you, that distinction is often the whole reason to use it.
The more useful thing to take away is where the repair belongs in the order of operations. It goes first, before cropping, before colour work, before resizing, because every one of those steps will otherwise carry the artefacts along and interact with them. And it does not belong at all if you can get the original file instead: a repair is an approximation of a picture you could simply ask for. Understanding how a picture accumulates damage across saves is what tells you whether you are looking at a fixable problem or a chain you should step out of.
The broader lesson is one that applies to more than JPEG. The reason a specialised model beats a general filter here is not that it is larger or newer. It is that the damage was not random in the first place. It was made by a specific process, with a specific block size and a specific ordering of what gets discarded first, and anything that knows that process has an enormous advantage over anything that treats the result as an unfortunate mess. Compression is not noise. It is a decision, made eight pixels at a time, and it can be partly argued with.