Digital · Exhibit 5
How do QR codes work?
Updated
A QR code is a link, or any short text, written in black and white squares. Every group of eight squares, called a codeword, holds one byte, which for a link like this one is one letter. Some codewords carry no text at all: they’re spares calculated from the others, and they’re why the code below still scans with a finger on it.
This one holds the address of this page. I sized the finger so the code only just survives at level M. It spoils 11 codewords, and M can repair 13. Tap L and the same finger kills it. Back on M, make it bigger. At 8% it uses the last repair, at 9% it’s gone. Then switch to H and see how big a finger it shrugs off.
How does a phone read a QR code, step by step?
The size of a QR code grows in steps called versions, from 21 squares a side at version 1 to 177 at version 40, four squares per step. The code above is version 3 at level M. Whatever the size, a phone reads it in the same order:
- It looks for the three big corner squares. A line through the middle of each crosses dark, light, dark, light and dark in the ratio 1:1:3:1:1.
- It straightens the picture. From version 2 on there are small alignment squares for this; the code above has one, near the bottom right corner.
- It works out the size from the distance between the corner squares; the timing lines, two dotted lines between them, help place the columns and rows. From version 7 on, the version number is also written in two small 6-by-3 patches.
- It reads the format strip: 15 squares, stored twice beside the corner squares, that name the error correction level and the mask. The strip has a repair code of its own and survives up to 3 wrong squares in a copy.
- It takes off the mask. Before a code is finished, one of eight masks flips the data squares in a fixed pattern, such as a checkerboard. The encoder tries all eight and keeps the one with the lowest penalty: points for long runs, solid 2-by-2 patches, shapes that could pass for a corner square, and too much dark or too much light. The phone flips the same squares back.
- It collects the codewords, two columns at a time, zigzagging up and down from the bottom right corner. In the code above, 7 squares are left over at the end and carry nothing.
- It repairs what it can, block by block (more on that below).
- It turns the bytes back into text: 01101000, for example, is the letter h.
DENSO WAVE, the company that invented the QR code, picked the 1:1:3:1:1 ratio after measuring black and white areas on flyers, magazines and cardboard boxes, where it turned up least often.
None of this needs the internet. The link is in the squares; only opening it goes online.
How much of a QR code can you cover?
Less than the level suggests. DENSO WAVE gives round figures for the four levels: about 7% of the codewords can be rebuilt at L, 15% at M, 25% at Q and 30% at H. Small codes like this one do a little better. At M it can lose 13 of its 70 codewords, about one in five, and at H 44 of 134, a third. But one changed square spoils a whole codeword, so the area you can cover is smaller than any of those.
I moved the toy’s finger over every spot on the code above that leaves the four positioning squares alone. At H the code still read with 20% of it covered in two spots out of three, and with 25% covered in none. At M about half the spots survive a finger over 10%, and at L about half survive 5%.
With the finger where it starts, 7% of the code already spoils 11 of the 70 codewords: the red squares outside the finger belong to codewords it only grazed.
A dark finger over dark squares changes nothing, and neither does a white sticker over white ones. Only the squares that flip count: with the finger where it starts, 29 of the 60 squares under it changed color.
Bigger codes are cut into blocks, dealt out like cards: neighboring codewords belong to different blocks, so a finger spreads its damage over all of them. Each block repairs only its own codewords. At level H the same link needs a bigger code, version 5, with four blocks that repair 11 codewords each, and it fails as soon as any one block gets a 12th.
Four spots are off limits at any level: the big squares in three corners and the small one near the bottom right. They carry none of the text, so the repair has nothing to do with them, but the camera needs them. Cover a corner square and a phone may not find the code at all; cover the small one and it may read the squares crooked. The toy draws a dashed frame around any of them you touch.
A logo in the middle of a QR code works for the same reason a sticker does: to the phone it’s just more spoiled codewords. It’s safest at level H and away from the corner squares, and it spends part of the repair budget, so a scratch on top of a logo can be the last straw.
A higher level also needs a bigger code for the same text: this one has 29 squares a side at M and 37 at H. Pick a level for your own code in the free QR code generator. I’d take M for a screen and Q or H for a label that gets dirty.
How does a phone repair a damaged QR code?
It works like the check digit on a bank card, except that a check digit can only tell you a number is wrong. The spare codewords are calculated from the text so that a damaged block no longer adds up, and the way it fails to add up tells the phone which codewords are wrong and what they should be. The method is called a Reed-Solomon code, the same kind of error correction music CDs use.
One spare can fix a codeword the phone knows is missing. A codeword that’s wrong but looks fine takes two, because the phone has to find it before it can fix it. A camera can’t tell a finger from a dark square, so decoders such as ZXing, the open-source library inside many scanner apps, hunt for the errors blind. That’s why level H, which adds the most spares, still repairs only about 30%.
In six of the smallest combinations (1-L, 1-M, 1-Q, 1-H, 2-L and 3-L) the standard, ISO/IEC 18004, tells decoders to hold one to three spares back. They catch the rare case where a repair would land on a different text that also checks out. The code on this page, 3-M, holds none. ZXing, and my decoder with it, ignores the rule and repairs up to half of all spares, so in 1-L, 1-M and 2-L it repairs one codeword more than the standard allows, using two of the held-back spares.
Does a QR code work upside down, mirrored or as a screenshot?
Upside down and as a screenshot, yes, as long as the white border stays around it. The corner squares sit in three corners, and the empty fourth corner tells the phone which way up the code is. A mirror image still has its three corner squares in an L, so the phone finds it, but it swaps the two outer corners and reads the squares in the wrong order. Mirrored, usually: ZXing and some other decoders try a mirrored reading when the normal one fails, but I haven’t tested phone camera apps. I mirrored the code on this page left to right and top to bottom and gave the pictures to ZXing in camera mode, and it read every mirror image at all four levels. The same setup missed the unmirrored code at level Q at 3 of 5 sizes. That’s a quirk of ZXing’s camera mode on small images (jsQR read every clean test image), not of the code.
A screenshot is just another picture of the code, and you can open one in the QR code checker to see the address in it without an app.
How many QR codes are possible, and can they run out?
They can’t run out, because nobody hands them out. A QR code is its text written in squares, so nothing is used up when you make one: the same link gives a code that reads the same, whichever generator draws it.
The largest version, 40 at level L, holds 2,953 bytes, and the number of different texts of exactly that length is 2,953 copies of 256 multiplied together: a number with 7,112 digits. Even the small code on this page holds 42 bytes at level M: 256 to the 42nd power possible texts, a number 102 digits long.
Scanova’s blog gives 2 to the power 31,329 as the ceiling, one free choice for each of the 31,329 squares of the largest code, and notes that the fixed patterns and repair bytes cut it down. They take about a quarter of those squares. That leaves 23,624 squares for text, eight for each of the 2,953 bytes, so there are 2 to the power 23,624 possible texts.
Can you trust the toy’s verdicts?
The code above comes from my own encoder, the same one the generator uses, and the verdicts come from my own decoder. Neither is worth much unchecked, so I check mine against ZXing on thousands of random covers, in its clean-grid mode: a flat picture, no camera, no blur, no angle. The first run caught a disagreement. The JavaScript port of ZXing has an old bug. It keeps a stopping rule that the Java original replaced in September 2021, after fuzz testing found it. I found it in version 0.21.3, and 0.23.0, the latest in October 2026, still has it. Now and then, in blocks with an odd number of spares, it repairs one codeword more than the code guarantees. A scanner built on it can read a code the toy calls dead. I side with the corrected rule, and the test patches the port the same way.
After that, on 2,000 random covers that left the corner squares alone (fingers, stickers, splashes and scratches, dark and light, 500 at each level), the two gave the same answer every time. Another 1,815 covers touched a corner square. I leave those out: my decoder starts from the grid and never looks for the corners, so for those covers the toy shows a warning and gives no verdict. Before I publish any change, the toy goes through the same test on 2,000 finger and sticker covers of the code you see here.
What this doesn’t check is your phone. The camera app uses its own decoder and sees blur, glare and an angle, so close to the limit your phone may give up a little earlier, or hold on a little longer, than the toy says.
What does the toy simplify?
- The finger is solid black and the sticker solid white. A real finger can come out black, white or patchy, depending on the light.
- There’s no camera: no blur, no glare, no angle, no curved paper. The decoder starts from a perfect grid of squares.
- It never searches for the corner squares, so when you touch one it can only warn you. The warnings about the corner and the small square come from how decoders find and straighten a code, not from a test with a real camera.
- Its verdicts are checked against one other decoder, ZXing, and only on a flat picture.
Sources
- DENSO WAVE, History of QR Code: the 1:1:3:1:1 ratio and how it was chosen.
- DENSO WAVE, Error correction feature: levels L, M, Q and H, Reed-Solomon codes; Versions: 21 to 177 squares a side.
- ISO/IEC 18004, the QR Code standard (paid; tables checked against the 2015 edition, the current one is 2024): layout of the code, blocks and error correction per version and level, and the spares kept for catching misreads.
- ZXing, ReedSolomonDecoder.java and the fix of September 2021; Decoder.java: the mirrored reading.
- zxing-js, ReedSolomonDecoder.ts: the old stopping rule in the JavaScript port.
- Scanova, How many QR codes are possible: the 2 to the power 31,329 ceiling.
QR Code is a registered trademark of DENSO WAVE INCORPORATED.