Anatomy of a QR code
Most of a QR code is not your data. Roughly a quarter of a small symbol is scaffolding that exists so a camera can find the code, work out how big it is, tell which way up it is, and know how to read the rest. Here is what each piece does.
It starts as a grid of a fixed size
A QR code is a square grid of black and white cells. The cell is called a module, and it is the unit everything else is measured in. The grid comes in 40 fixed sizes, called versions. Version 1 is 21 modules across. Every version after it adds four modules to each side, so version 2 is 25, version 3 is 29, and version 40 is 177.
You do not choose the version directly. The encoder picks the smallest one that will hold your content at the error correction level you asked for. This is why adding a few characters to a URL sometimes makes the pattern visibly denser and sometimes changes nothing: you either crossed a version boundary or you did not.
Three squares that make the code findable
The three large concentric squares in the corners are finder patterns. Each is seven modules across: a dark 7x7 outline, a light ring inside it, and a solid dark 3x3 in the middle. Any straight line drawn through the center of one crosses dark and light runs in the ratio 1:1:3:1:1.
That ratio is the whole trick. It holds at any rotation and, importantly, at any scale, so a scanner can sweep lines across a camera frame looking for that one signature without knowing where the code is, how large it is, or which way it is turned. Find three of them and you have located a QR code and established its orientation, because the missing fourth corner tells you which way is up.
Each finder is surrounded by a one-module light separator, so the pattern cannot bleed into neighboring data and break the ratio.
Timing strips and alignment patterns fight distortion
Between the finder patterns run two lines of alternating dark and light modules, one horizontal and one vertical. These are the timing patterns, and they let a scanner count modules rather than measure millimeters. Without them, a code photographed slightly out of square would have its grid misjudged and every module read from the wrong place.
From version 2 onward there are also alignment patterns: smaller 5x5 concentric squares scattered through the symbol. Bigger codes get more of them. They exist because paper curves, labels wrap around bottles, and phone lenses have barrel distortion. Three corner points define a perfect square; the alignment patterns give the decoder extra fixed points inside the symbol so it can correct for a grid that has been bent rather than merely rotated.
Format and version bits: the code describes itself
A scanner that has found the code still does not know how to read it. Two small fields tell it.
- Format information: 15 bits sitting alongside the finder patterns, carrying the error correction level and which of the eight mask patterns was applied. It is protected by its own error-correcting code and written twice, in two different places, because nothing else can be read until it is.
- Version information: 18 bits, present only on version 7 and above, in two blocks near the top-right and bottom-left finders. Smaller codes do not need it, since counting the modules between the finders gives the version away.
Both fields are heavily redundant relative to their size. That is deliberate. A damaged data module costs you a fraction of one character; a damaged format module, unprotected, would cost you the entire symbol.
The data is laid out in a snake, not in rows
Everything left over after the scaffolding is the data region. Bits are not written in reading order. They are placed in a column two modules wide, starting at the bottom-right corner and moving upward, then the next two-module column moves downward, and so on across the symbol, skipping any module already claimed by a finder, a timing strip, an alignment pattern or a format field.
Before placement, the content is split into codewords of eight bits, and those codewords are interleaved with the error correction codewords rather than kept in separate regions. The point of interleaving is that a coffee ring, a staple or a thumb covers one area of the symbol, and interleaving turns that one concentrated injury into a few scattered errors across many blocks, which is the shape of damage the correction maths is good at.
Masking is why two codes for the same text can look different
Raw encoded data often produces ugly patterns: large blank areas, long dark runs, or accidental 1:1:3:1:1 sequences that look like a finder pattern and send the decoder hunting in the wrong place. So the encoder applies a mask, which is a fixed geometric pattern XORed over the data region only, flipping some modules.
There are eight masks. The encoder generates all eight, scores each against a set of penalty rules in the standard, and keeps the lowest score. The choice is recorded in the format bits, so the decoder simply XORs the same pattern back off.
This is the honest answer to why the same URL encoded by two tools can produce two different-looking codes that both scan. Different mask choice, or a different encoding mode, or different padding. All of them are valid.
Four ways of writing the same characters
How efficiently your content packs depends on which alphabet it uses. The standard defines several modes, and an encoder picks the tightest one your content allows.
| Mode | Character set | Roughly |
|---|---|---|
| Numeric | Digits only | 10 bits per 3 digits |
| Alphanumeric | Digits, A-Z uppercase, space, $%*+-./: | 11 bits per 2 characters |
| Byte | Anything, commonly UTF-8 | 8 bits per byte |
| Kanji | Shift JIS double-byte characters | 13 bits per character |
The practical consequence is that case matters for size. Alphanumeric mode has no lowercase letters in it, so a URL written in capitals can encode more compactly than the same URL in lowercase, which falls back to byte mode. Domain names are case-insensitive, so uppercasing the host is free. It is a real trick, though it usually only saves you a version or two.
The empty margin is part of the code
The specification requires a clear margin of four modules on every side, called the quiet zone. It is not styling. The finder-pattern ratio is measured by looking at runs of dark and light, and a dark object touching the edge of the symbol corrupts the run that identifies it.
Cropping the quiet zone is one of the most common ways a code that worked in the design file stops working in print, because it usually happens in layout rather than in the generator. If the code sits on a colored panel, the quiet zone has to be part of the light area, not the panel.