How this is worked out
A QR code is a grid of black and white squares — "modules" — arranged by ISO/IEC 18004. Four things happen to turn your text into one.
The text is encoded in the tightest mode that fits. Digits pack three characters into ten bits, uppercase-and-digits packs two into eleven, and everything else uses eight bits per byte. Picking the right mode is why a phone number produces a small code and the same number of lowercase letters produces a larger one.
Error correction codewords are added using Reed-Solomon arithmetic over a 256-element finite field. This is what lets a damaged, dirty or partly covered code still scan — the redundancy is genuine mathematics, not a duplicate copy.
The data is laid out in a zig-zag from the bottom right, skipping the finder patterns, timing patterns and alignment patterns that a scanner uses to locate and orient the code.
A mask is applied. All eight standard mask patterns are tried, each is scored with the penalty rules from the specification, and the lowest-scoring one wins. The scoring exists to avoid large blocks of one colour and to avoid accidentally creating something that looks like a finder pattern — both of which make a code hard or impossible to scan.
All of it runs in your browser. The encoder is part of this site rather than a library fetched from somewhere else, so no third party learns that you made a code, let alone what is in it.
A worked example
- Content
- https://editingtools.pro
- Encoding mode
- byte
- Error correction
- Medium — recovers ~15%
- Version chosen
- 2 (25 × 25 modules)
- Data codewords
- 28
- A wifi payload instead
- WIFI:T:WPA;S:My Cafe;P:secret;;
- Maximum any QR can hold
- about 2,950 bytes
- Sent to a server
- nothing
Why "generated on our server" should worry you
Most free QR generators build the code on their server. That means the thing you encoded — a wifi password, a private document link, a customer's contact details — was transmitted to a company you know nothing about, and may well be sitting in a log.
The wifi case is the sharpest example. A wifi QR code contains your network password in plain text, unencrypted, as part of the payload. Encoding one through a server hands over the password to your home or business network. There is no version of that which is acceptable, and almost nobody thinks about it, because the tool feels like a calculator rather than a form.
This page encodes in your browser using an encoder that is part of the site. There is no upload, and there is no library fetched from a CDN either — so no third party even learns that you were making a code. You can confirm all of it in your browser's network tab: this site makes no external requests at all.
Error correction, and the logo in the middle
The four levels recover roughly 7%, 15%, 25% and 30% of the code. Higher correction means more redundancy, which means a physically larger code carrying the same data — the trade is size against robustness.
Medium is the sensible default for a screen or a clean printed sheet. Go to Quartile or High for anything that will be printed small, put on packaging, stuck to a window, or left outdoors where it will get rained on and scuffed.
High is also what makes the logo-in-the-middle trick work. Covering the centre destroys those modules, and the error correction reconstructs them — but only up to its limit. Keep the covered area under about 25% of the code even at High, never obscure the three corner finder patterns, and always test the result with an actual phone before printing a thousand of them.
Print it as vector, and leave the quiet zone alone
Download the SVG for anything that will be printed. It is vector, so it stays perfectly sharp at any size — a business card or a billboard from the same file. A QR code printed from a low-resolution bitmap, where the module edges have gone soft and grey, is the single most common reason a code will not scan.
The white margin around the code is called the quiet zone and it is part of the specification, not decoration. Four modules of clear space on every side is the requirement, and cropping it off — or placing the code tight against a coloured background — is the second most common reason a code fails.
Contrast matters too, and in one direction specifically: the dark modules must be darker than the light ones. Inverted codes, where a light pattern sits on a dark background, are not reliably readable by many scanners. And never print a QR code smaller than about 2cm square, whatever the version.
What a QR code is not
It is not encrypted, and it is not private. Anyone who can photograph the code can read exactly what is in it — a QR code is a way of writing text that a camera can read, and nothing more. Do not put anything in one that you would not write on a postcard.
It is also not dynamic. A printed QR code is fixed forever; the only way to change where it points is to encode a link you control and change the destination at your end. "Dynamic QR" services do exactly that, which also means the code stops working the day that company shuts down or starts charging.
And a QR code cannot be trusted just because it is a QR code. A sticker placed over a legitimate one — on a parking meter or a restaurant table — is a genuinely common scam, because nobody can read a QR code by eye to check where it goes. Look at the URL your phone shows you before tapping it, exactly as you would with a link in an email.
Assumptions and sources
- Standard
- ISO/IEC 18004. Versions 1–40, error correction levels L/M/Q/H, numeric, alphanumeric and byte modes, Reed-Solomon over GF(256) with the 0x11D primitive polynomial.
- Encoder
- Written for this site in assets/js/tools/qr-encode.js. No third-party library, no CDN, no server.
- Verification
- Every code is round-tripped in tools/test/qr.mjs — encoded here and decoded by an independent decoder across all modes, all four correction levels and versions 1 to 40. A QR encoder can produce a perfect-looking matrix that nothing can read, so a round trip is the only test that means anything.
- Payload formats
- WIFI:, mailto:, tel:, SMSTO: and vCard 3.0 are scanner conventions rather than part of the QR standard itself. Semicolons and backslashes in wifi fields are escaped, which is a common cause of a code that "does not work".