A phone camera reads a QR code in a few milliseconds or not at all. There is no partial credit and no explanation. This is what is going wrong when it fails, measured on real photographs rather than guessed at.
A scanner takes one look
A QR code is a grid of black and white squares called modules. To read one, a scanner has to find the three large squares in the corners, work out where every module sits, decide whether each is black or white, and hand the resulting bits to an error-correcting decoder. Each of those steps has one attempt. If the grid is placed half a module out, or a few hundred squares are read the wrong colour, the decoder fails and the scanner simply shows nothing.
That is the right trade for a scanner: it is looking at a live camera feed and can try again on the next frame. It is the wrong trade for a photograph, where there is no next frame — and it is why a picture that plainly contains a readable code can defeat every app on the phone.
Blur alone is survivable
Ordinary defocus blur spreads each module's brightness into its neighbours evenly. A module that should be black gets lighter, one that should be white gets darker, and the two populations move towards each other. As long as they stay separated, a threshold picked in the middle still sorts them correctly, and the code reads.
What kills the read is not blur but asymmetry.
Photographing a screen is the hard case
Point a camera at a monitor, a projector or a phone showing a QR code and the bright areas bleed outwards into the dark ones. The effect is not symmetric: white spreads into black far more than black spreads into white. A white module hemmed in by dark neighbours simply survives; a dark module surrounded by white gets eaten.
Here is that effect measured on a photograph of a projected slide. Each module was scored by how far it sat from the decision threshold, in the direction of "dark":
| Module type | Lowest | Median | Highest |
|---|---|---|---|
| Genuinely dark modules | +16.3 | +23.0 | +26.4 |
| Genuinely light modules | −43.0 | −3.5 | +26.1 |
The dark modules form a tight cluster. The light modules spread enormously, and the worst of them land inside the dark cluster — reading as confidently dark as a real dark module. Those are not modules that were dimmed and could be rescued by a better threshold. They were overwritten. The information about them is no longer in the photograph.
This has a practical consequence that surprises people: on a photographed screen, the errors run one way only. A module read as light is almost certainly light. Only the ones read as dark are suspect.
How much damage is too much
Every QR code carries error correction, so a handful of misread modules costs nothing. The question is how many is a handful. That depends on the error-correction level the code was made with, which is recorded in the code itself and can be read even from a badly damaged picture.
Codes are built from blocks of 43 codewords, each codeword eight modules. At level M a block carries sixteen parity symbols, and roughly a fifth of its codewords may be corrupt before the payload is gone for good. Translated into module error rates, recovery is realistic below about:
| Error-correction level | Module error rate it tolerates |
|---|---|
| L | about 2% |
| M | about 3% |
| Q | about 6% |
| H | about 8% |
Above the ceiling for its level, no tool recovers the link, because the link is not in the file any more. Below it, a photograph a scanner rejects outright is often perfectly recoverable — the scanner gave up after one attempt, not because the data was missing.
Measuring the damage instead of guessing
There is a way to find out which side of that line a picture falls on, and it does not involve squinting at it. Parts of every QR code are fixed by the specification — the three corner squares, the thin lines of alternating modules that run between them, the small alignment square. Their values are known before anything is decoded, so they can be read and checked.
One caution, learned the hard way on this project. The alternating lines are the hardest modules in the whole symbol: isolated single squares with neighbours of the opposite colour, exactly the arrangement that bloom destroys. On one photograph they read at 6% error while the actual data region was nearer 2.5%. Scoring a photograph on those alone will tell you it is hopeless when it is not.
The recovery tool on this site reports both figures, and reports what the code's own blocks say when Reed-Solomon is run against them — which is the only measurement that settles it.