Projects/Build a QR Code Encoder

Build a QR Code Encoder

The core is Reed-Solomon error correction over GF(256), and every value is pinned to the known HELLO WORLD worked example: the exp/log tables of the field, the generator polynomial coefficients, the exact 13 data and 13 error-correction codewords, the finder pattern layout, the zigzag data path, the lowest-penalty mask, and the BCH format bits. Each lesson is one concrete spec with exact field elements, codewords, or matrix modules - and the capstone asserts the finished 21x21 grid module for module against the reference.

38 lessonsMedium~20 min / lessonReed-SolomonGalois fieldsError correction
The project

What you'll build over the next 38 lessons

Over 38 lessons you build a working QR code encoder from first principles, as a library: give it a string and it returns the boolean module grid - the black-and-white square pattern - that a real scanner reads back. The whole project is anchored to one fully worked example, the string HELLO WORLD as a Version 1, error-correction level Q symbol, so every intermediate value (field element, codeword, matrix module) is a concrete number you assert against.

You start in the finite field GF(256), the arithmetic that error correction runs on: addition is XOR, multiplication reduces by the polynomial 0x11D, and log and antilog tables make it fast. On that field you build Reed-Solomon error correction - the generator polynomial and polynomial division that produce the recovery codewords. Then you encode text into a bitstream (modes, character counts, padding), split it into data and error-correction codewords, and lay out the 21x21 grid: the three finder patterns, timing lines, the dark module, the zigzag data path, the eight mask patterns scored by four penalty rules, and the BCH-protected format information. The capstone encodes HELLO WORLD end to end and asserts the finished grid equals the known-good reference, module for module - a symbol a real scanner decodes.

This is an encoder, not a scanner: it turns text into the module grid, and the reference build is deliberately scoped to Version 1 (the smallest 21x21 symbol) across all four error-correction levels, with the full Reed-Solomon and masking pipeline that larger versions reuse. You build both an alphanumeric and a byte-mode encoder; the end-to-end pipeline drives the worked example through alphanumeric mode, and a finishing command-line tool renders any input as ASCII blocks. Reading a QR back from a camera photo is the opposite problem - perspective correction and image processing - and is a separate, much larger project, so it is out of scope here. What you finish with is the honest core of every QR generator: the field arithmetic, error correction, and layout that scale up to the bigger versions by extending the same code.

build-a-qr-code-encoder / lesson-01.md
Lesson 01 · GF(256), the field of QR

Addition is XOR

Every byte in a QR code's error correction lives in a finite field called GF(256), where the very first surprise is that adding two values means XOR-ing them. Today you write that one operation - the arithmetic everything else in the project stands on.

The goal

Add two field elements by XOR-ing their bytes, and confirm a value plus itself is zero.

Start here - the target
TO DO
Scenario: Field addition is a byte XOR
Giventwo GF(256) elements 0x40 and 0x05
Whengadd(0x40, 0x05) is called
Thenit returns 0x45
Andgadd(0xA3, 0xA3) returns 0x00 - any element added to itself is zero, so in this field subtraction is the same operation as addition
Background

QR codes recover from damage using Reed-Solomon error correction, and that math does not run on ordinary integers. It runs on a finite field written GF(256): a set of exactly 256 values (all the bytes) with its own rules for add, subtract, multiply, and divide, where every operation stays inside the set. The whole first chapter builds this field, because every codeword you compute later is an element of it.

The friendliest rule comes first. Addition in GF(256) is bitwise XOR. There are no carries, so 0x40 + 0x05 is 0x45 (the bits never collide) and, crucially, a value XOR-ed with itself is 0. That last fact means subtraction is the same as addition - to subtract, you XOR, exactly as you would to add. Keep that in mind: later, when a formula says “minus”, you will reach for the very same gadd.

Make it work
// A GF(256) element is just a byte. Addition and subtraction
// are the identical operation here: bitwise XOR.
func gadd(a, b byte) byte {
return a ^ b
}
CheckpointDONE
You can add and subtract in GF(256). Commit and stop here.
Scope & extensions

Where this project stops - and where to go next

A fully working, spec-correct Version 1 (21x21) QR encoder across all four error-correction levels - real GF(256) arithmetic, Reed-Solomon error correction, bitstream encoding with padding, block interleaving, function-pattern layout, eight masks scored by the four penalty rules, and BCH format information - producing a grid a real scanner reads, wrapped in a runnable command-line tool; but it stops at Version 1, drives its end-to-end pipeline through alphanumeric mode (the byte-mode encoder is built but not wired into the full Encode path), and has no decoder.

Extend it next
  • Wire the already-built byte-mode encoder into the end-to-end pipeline with real mode selection, and add numeric mode (three digits per 10 bits) to round out the common modes
  • Support higher versions (2 through 40): larger grids, longer character-count fields, and the alignment patterns that appear from Version 2 on
  • Connect the splitBlocks and interleave helpers to real multi-block capacity tables (Versions 5-Q and up split data into several blocks) instead of the single-block Version 1 case
  • Add automatic version and mode selection: pick the smallest version and most compact mode that fits the input at the requested error-correction level
  • Write a decoder as a companion project: image binarization, finder-pattern detection, perspective correction, and Reed-Solomon error correction to recover the data (and to round-trip-verify scannability)
Recommended reading

Books & references that go deeper

  • QR Code Tutorial · Thonky.com

    The clearest step-by-step walkthrough of encoding a QR symbol, and the source of this project's worked example: it encodes HELLO WORLD as a Version 1-Q symbol all the way to the final matrix, with every codeword, error-correction codeword, and module shown. Check your values against it lesson by lesson.

  • The authoritative standard: the mode indicators, character-count bit lengths, error-correction block structure, the generator polynomials, the mask patterns and penalty rules, and the BCH format/version information. The final word when a tutorial is ambiguous.

  • A from-scratch, code-first derivation of exactly the Reed-Solomon variant QR uses: GF(256) arithmetic with the log/antilog tables, the generator polynomial, and encoding as polynomial remainder. The practical companion to this project's middle chapters.

  • The GF(2^8) primer behind the first chapter: why addition is XOR, how multiplication reduces modulo an irreducible polynomial (QR uses 0x11D), and how the primitive element 2 generates the field through its powers.

  • An interactive, rigorously correct reference implementation with a live visualizer for every stage - segments, error correction, mask selection, and the final matrix. Excellent for cross-checking the layout and masking chapters.