Spec & internals
Decode a QR code by hand
To decode a QR code by hand, orient the symbol using its three finder patterns, read the 15-bit format information (XOR with 101010000010010), apply the named mask to the data region, read modules in zig-zag order, de-interleave the codewords, verify with Reed–Solomon, then parse mode indicators to recover the text.
What you need
A printed or on-screen code, graph paper, and patience. Pick a small symbol — a version 1 (21 × 21) or version 2 (25 × 25) code — because the work grows with the square of the side. This page is the reverse of encoding "hello world" by hand; doing both once teaches you more about QR than any amount of reading.
Copy the symbol onto graph paper as a grid of dark and light cells. The side length tells you the version: modules per side = 17 + 4 × version, so 21 means version 1, 25 means version 2, and so on.
Step 1 — orient and read the format information
The three finder patterns belong at top-left, top-right and bottom-left. If the empty corner is anywhere but bottom-right, rotate (or un-mirror) your copy.
The 15-bit format information runs along the edges of the top-left finder. Read it, then XOR with the fixed masking constant 101010000010010 (0x5412) — the spec applies this so the format field is never all zeros. The first two resulting bits give the error correction level, the next three name the mask:
| EC bits | Level |
|---|---|
| 01 | L |
| 00 | M |
| 11 | Q |
| 10 | H |
The remaining 10 bits are BCH error correction over the field itself. A second, identical copy sits split beside the other two finders — read it if the first is damaged.
Step 2 — remove the mask
Every data module was XORed with a mask pattern at encode time. Apply the same pattern again to undo it: for mask 0, flip every module where (row + column) mod 2 = 0; each of the eight masks has a similar coordinate formula. Only data and error-correction modules are masked — leave finders, timing patterns, alignment patterns and the format information untouched.
Step 3 — read the zig-zag
Data is stored in two-module-wide columns, starting at the bottom-right corner, running upward, then down the next pair, alternating. Within each pair read right cell then left cell. Skip every function-pattern module and skip column 6 entirely (the vertical timing pattern) — the walk simply steps over it. Dark = 1, light = 0. Group the bits into 8-bit codewords.
Step 4 — de-interleave and check Reed–Solomon
For version 1 there is a single block, so the codewords are already in order. Larger versions interleave codewords from multiple blocks — codeword 1 of block 1, codeword 1 of block 2, and so on — and you must deal them back out using the block table for your version and level.
A full Reed–Solomon check means computing syndromes over GF(256): all zeros confirms an undamaged code. By hand, most people (reasonably) assume a cleanly printed code is intact and move on.
Step 5 — parse the bit stream
Now read the data codewords as a bit stream:
| First 4 bits | Meaning |
|---|---|
| 0001 | Numeric mode |
| 0010 | Alphanumeric mode |
| 0100 | Byte mode |
| 1000 | Kanji mode |
| 0000 | Terminator — stop |
After the mode indicator comes a character count (8 bits for byte mode at versions 1–9), then the data itself — in byte mode, each 8 bits is one character. Decode until you hit the terminator; everything after it is padding (the alternating bytes 11101100 and 00010001).
If you want to check your work, point /scan at the code, or feed the payload to /validate and compare.
FAQ
How do I know which mask a QR code used?
Read the 15 format bits beside the top-left finder pattern, XOR them with 101010000010010, and take bits three to five of the result. They name one of the eight mask patterns, each defined by a simple coordinate formula.
Can you really decode a QR code without a computer?
Yes, for small versions. A version 1 code holds at most 152 data bits, and every step — unmasking, the zig-zag read, mode parsing — is pencil-and-paper arithmetic. Verifying the Reed–Solomon codewords by hand is the only genuinely tedious part.
Why do the bits I read look like random noise?
You probably forgot to remove the mask. Raw modules are XORed with a mask pattern precisely so they look balanced and noise-like; undo the mask named in the format information before reading the zig-zag.
What order are QR code bits stored in?
In two-module-wide columns starting from the bottom-right corner, running alternately up and down, right cell before left cell, skipping all function patterns and the vertical timing column. Bits group into 8-bit codewords, most significant bit first.
Try it — free, no signup
Related
- Encode HELLO WORLD by hand — a complete worked example — The classic exercise: HELLO WORLD as a version 1-Q QR code, step by step, with every real intermediate value from character pairs to Reed–Solomon codewords.
- QR code bit stream walkthrough — from text to modules — The full encoding pipeline: mode indicator, character count, data, terminator, pad bytes 0xEC 0x11, Reed–Solomon, interleaving, zig-zag placement, masking.
- Format information — the 15 bits everything depends on — Format information encodes the EC level and mask in 5 bits, protects them with BCH(15,5), XORs with a fixed mask, and is written twice beside the finders.
- Mask patterns 0 to 7 — the eight formulas and why they exist — Every QR code XORs its data region with one of eight fixed patterns to break up problem shapes. The formulas, what they look like, and what masking prevents.
- QR code anatomy — every region of the symbol — A labelled tour of a QR code: finder patterns, separators, timing, alignment, format and version information, the data region and the quiet zone.