Position Detection Patterns
Before any data can be decoded the scanner must first find and orient the code. These compulsory elements are the foundation of every QR code.
The Three Corner Anchors
Every QR code starts with three identical markers — one each in the top-left, top-right, and bottom-left corners. Each has a 7×7 black outer ring, white middle ring, and solid 3×3 black centre — a ratio that never appears in ordinary data.
The Timing Patterns along row 6 and column 6 alternate black/white, letting the decoder count rows and columns precisely. Drag the slider to see alignment patterns appear from version 2 onward.
The missing bottom-right marker acts as a rotation cue — a scanner determines orientation just from which corner lacks a marker.
Format Information
15 bits wrapped around the top-left finder — and duplicated across the other two corners — tell the scanner how to decode everything else.
Three Parts, 15 Bits
EC Level (2 bits) — sacrifices capacity for recovery redundancy.
Mask (3 bits) — which XOR pattern was applied to the data area.
BCH check (10 bits) — BCH(15,5) error correction on the 5 data bits, then XOR'd with 101010000010010 to prevent all-zero sequences.
If an entire corner is torn off, the other copy is used. BCH covers bit errors within one copy; the duplicate survives total corner loss.
Mask Patterns
After placing data, one of 8 XOR patterns is applied to every data module. Where the formula is true, the module flips. Structural modules are never masked. The encoder scores all 8 and picks the lowest-penalty result.
Interactive QR Structure
All structural layers combined. Each element type is colour-coded. The mask is actually applied to the data. Toggle blank data to see the mask pattern directly.
Data Encoding
Before any bits reach the grid, raw data is packaged into a specific bitstream. Here is how it is structured.
Bitstream Structure
ENC — Mode Indicator (4 bits) — tells the decoder which encoding scheme was used:
| Bits | Mode | Characters | Efficiency |
|---|---|---|---|
| 0001 | Numeric | 0–9 only | 3 digits / 10 bits |
| 0010 | Alphanumeric | 0–9, A–Z, $%*+–./: | 2 chars / 11 bits |
| 0100 | Byte | Any binary / text | 1 byte / 8 bits |
| 1000 | Kanji | Shift-JIS | 1 char / 13 bits |
LEN — character count. Width varies by version and mode (for byte mode: 8 bits in versions 1–9, 16 bits in versions 10–40).
DATA — in byte mode each character is its ISO 8859-1 byte value, identical to ASCII for characters below 128. Modern encoders use UTF-8 with an ECI header for non-Latin text.
After data: a 0000 terminator, byte-boundary padding zeros, then alternating 11101100 / 00010001 padding bytes to fill remaining capacity. The block is then Reed-Solomon encoded — that is the next layer.
A URL with only digits and uppercase letters uses Alphanumeric mode (~30% more capacity), giving a less dense, easier-to-scan code.
Encode Text
Type any short text and see it converted to bytes, then watch each byte's bits placed onto the QR code grid in the zigzag order the spec defines.
Reed-Solomon Error Correction
That grey area from §6 — now explained. RS adds check bytes so a scanner can reconstruct data even when part of the code is torn, dirty, or obscured.
The core idea
Imagine fitting a curve through a set of points. If you know the curve has a certain shape, a handful of damaged points can be reconstructed from the undamaged ones. RS does exactly this — for bytes instead of geometric points.
Step 1 — treat the data as a polynomial. Each data codeword becomes a coefficient: D(x) = d₀x^(n-1) + d₁x^(n-2) + … + d_(n-1).
Step 2 — divide by the generator polynomial G(x) = (x−α⁰)(x−α¹)···(x−α^(ec-1)), where α is a primitive element of GF(256). The remainder R(x) = D(x) mod G(x) gives the EC codewords.
Step 3 — append the remainder. The final block is D(x)·x^ec + R(x), which is exactly divisible by G(x). That divisibility lets the scanner detect and fix errors.
All arithmetic runs in GF(256): a "Galois Field" of 256 elements (every byte). Addition = XOR. Multiplication uses precomputed exp/log tables built from the primitive polynomial x⁸+x⁴+x³+x²+1. Once gfMul(a,b) works, the rest is polynomial long division — about 20 lines of code.
For larger QR versions the data codewords are split into 2–4 groups (blocks) and each block gets its own independent RS computation. The resulting data and EC codewords are then interleaved — a burst of damage that hits several consecutive modules only destroys one codeword per block, keeping errors correctable.