How a Scratched QR Code Still Scans
QR codes carry redundant data computed with Reed–Solomon coding, which is why a torn corner or a logo pasted in the middle usually doesn't stop them.
Print a QR code, scribble across a corner of it, and it still scans. Paste a company logo over the middle and it still scans. This isn't luck or a forgiving scanner — the redundancy is designed in, it's mathematically precise about how much damage it can absorb, and you choose the amount when you generate the code.
The data isn't stored once
A QR code's contents are encoded into codewords, 8-bit symbols. Before anything is drawn, the encoder computes additional error correction codewords from the data using Reed–Solomon coding, and stores both. A scanner that reads a damaged code uses the error correction codewords to work out what the missing or corrupted data codewords must have been.
There are four levels, and they trade capacity for resilience:
| Level | Recovery capacity | Rough overhead |
|---|---|---|
| L (Low) | ~7% of codewords | smallest code |
| M (Medium) | ~15% | default in most generators |
| Q (Quartile) | ~25% | |
| H (High) | ~30% | largest code |
Those percentages are of codewords, not of the picture's area, which is a distinction that matters later.
What Reed–Solomon actually does
Reed–Solomon treats a block of data codewords as the coefficients of a polynomial over a finite field — for QR codes, GF(256), the field with 256 elements, which is convenient because each element is exactly one byte. The encoder evaluates that polynomial at a set of fixed points and stores the results as the error correction codewords.
The useful property is the one that makes polynomials work at all: a polynomial of degree k−1 is completely determined by any k of its values. Two points determine a line, three determine a parabola, and so on. If you store n points for a polynomial that only needed k, then losing any n−k of them costs you nothing — the remaining points still pin down the same polynomial, and the original coefficients fall out of it.
That gives a hard bound. With n − k extra codewords, the decoder can correct up to (n − k)/2 codewords that are wrong, or up to n − k codewords whose positions are known to be missing. The factor of two is the interesting part: an erasure at a known position is exactly twice as cheap to repair as an error at an unknown one, because with an error the decoder has to spend half its redundancy figuring out where the corruption is before it can figure out what the value should be.
QR scanners get some of this for free. If a region of the image is unreadable — too blurry to threshold, or physically absent — the decoder can mark those positions as erasures rather than guessing at them, and stretch the redundancy further.
Reed–Solomon is not exotic. The same scheme, in different parameterizations, protects CDs and DVDs, DSL lines, and deep-space telemetry. It's particularly good at burst errors: because each field element is a whole byte, a scratch that destroys eight consecutive bits damages one codeword rather than eight, which is exactly the failure mode physical media produce.
Interleaving: why the damage has to be spread out
There's a catch. Larger QR codes don't compute one giant Reed–Solomon block; they split the data into several blocks, each with its own error correction codewords. Each block can only repair its own share.
If the blocks were stored one after another, a single big blot would wipe out one entire block — past its correction capacity — while leaving the others untouched and unable to help. So the specification interleaves them: it writes the first codeword of every block, then the second of every block, and so on, before placing the result into the module grid along a fixed zigzag path.
The effect is that a compact area of damage is spread evenly across all blocks, so each one loses a manageable few codewords rather than one losing everything. This is why the practical damage tolerance is roughly uniform across the symbol, and also why the "30%" figure for level H should be read carefully: it's 30% of codewords per block, and a very concentrated blot can still exceed one block's budget even when the total damaged area is under the headline number.
What can't be damaged
Some parts of the symbol aren't data and carry no error correction of their own.
- The three finder patterns — the big concentric squares in the corners — are what a scanner searches for first to locate and orient the code. Destroy one and there's nothing to decode.
- The timing patterns, the alternating rows and columns between finders, establish the module grid so the scanner knows where each cell's center is.
- The alignment patterns, the smaller squares in larger versions, correct for perspective distortion when the code is photographed at an angle or on a curved surface.
- The format information near the finders records the error correction level and mask pattern. It has its own separate, heavier protection and is stored twice, because without it nothing else can be interpreted.
So the redundancy budget applies to the data region. A logo in the center consumes data modules, which is why that trick works; a sticker over a corner finder does not, which is why that one doesn't.
Masking, and why codes look scrambled
One more piece explains the visual texture. After the data and error correction bits are placed, a mask pattern is XORed over the data region. QR defines eight of them, and the encoder tries each, scores the result against penalty rules, and keeps the best.
The rules penalize large uniform areas, runs of five or more identical modules in a line, and — most importantly — any 1:1:3:1:1 ratio pattern that resembles a finder. The goal is to keep the module distribution roughly balanced and avoid accidentally drawing something that looks like a locator in the middle of the data. That's why two QR codes encoding almost identical text can look completely different: they may have chosen different masks.
Practical guidance
- Level M is the right default for a code that will be displayed on a screen or printed cleanly. Higher levels add modules, which makes each module smaller at a fixed physical size — and small modules are harder to scan, which can cost you more reliability than the extra redundancy buys.
- Level H is for codes that will be abused: printed on a curved surface, stuck outdoors, or covered by a logo. If you're embedding artwork, H and a conservative logo size — keeping the covered area well under the theoretical budget, since interleaving spreads but doesn't eliminate concentration — is the combination that survives.
- The quiet zone is not optional. A margin of four modules of blank space around the symbol is part of the specification. Codes that fail to scan against a busy background are often failing here rather than anywhere in the data.
- Shorter content scans better. Fewer characters means a lower version number, which means fewer and larger modules at the same physical size. Encoding a shortened link rather than a long one with tracking parameters is the single easiest reliability win, and a QR generator fed a short URL produces a visibly simpler symbol than one fed the raw address.
The reason a QR code tolerates damage isn't that it's drawn robustly. It's that it never stored just your data in the first place.
