1. What Is a QR Code? (TL;DR)
A QR code (Quick Response code) is a two-dimensional barcode made of black and white squares (“modules”) on a grid. It can store text, URLs, binary data, or structured payloads and be scanned rapidly from multiple angles by cameras. Compared with 1D barcodes, QR codes hold more data, are orientation-independent, and include robust error correction.
2. A Short History & Timeline
- 1992–1993: Denso engineers explore 2D codes for automotive part tracking.
- 1994: Denso Wave officially invents the QR Code; speed and robustness are key goals.
- 1997: First public spec in Japan (JIS X 0510).
- 2000: International standardization via ISO/IEC 18004.
- 2004–2010: Mobile phones and data networks drive adoption in Asia.
- 2010s: Global use for marketing, payments, and authentication.
- 2020–2022: COVID-19 accelerates mainstream, contactless usage worldwide.
- Today: Ubiquitous across industries, with open/royalty-free implementation.
3. Anatomy of a QR Code
Standard (Model 2) QR codes contain predictable structural elements:
- Finder Patterns (×3): Large squares at three corners for detection & orientation.
- Separators: White modules around finders.
- Timing Patterns: Alternating modules to determine grid spacing.
- Alignment Patterns: Smaller targets used for distortion correction (versions ≥ 2).
- Format Information: 15 bits storing EC level and mask pattern (with BCH protection).
- Version Information: 18 bits (versions ≥ 7) encoding the version number (also BCH-protected).
- Data & Error Correction Codewords: The payload and parity bytes.
- Quiet Zone: 4-module white margin around the symbol.
4. How Encoding Works: From Text to Modules
- Choose the smallest version (size) that fits data + chosen EC level.
- Select a data mode (numeric, alphanumeric, byte, Kanji, ECI).
- Create a bit stream: mode indicator → character count → encoded data.
- Add terminator bits and pad to full codewords.
- Generate Reed–Solomon parity codewords.
- Interleave data & EC codewords per spec.
- Place bits in the matrix in a zig-zag traversal.
- Try all 8 masks, score, and pick the best.
- Insert format & version info bits.
4.1 Choosing the Mode
- Numeric: digits 0–9; ultra-compact (10 bits per 3 digits).
- Alphanumeric: 45-char set (0–9, A–Z, space, $%*+-./:); 11 bits per 2 chars.
- Byte: 8-bit bytes (UTF‑8 or arbitrary binary).
- Kanji: Shift JIS mapping for common Japanese characters.
- ECI: Extended Channel Interpretation for non-default encodings.
Encoders can switch modes mid-stream to save space.
4.2 Character Count Indicator
The bit-length varies by mode and version range (1–9, 10–26, 27–40). Example: numeric uses 10/12/14 bits respectively.
4.3 Converting to Data Codewords
Bits are grouped into 8-bit codewords. Add terminator bits (≤4 zeros), then pad with 0xEC and 0x11 alternately until full.
4.4 Error Correction with Reed–Solomon Codes
- Treat data codewords as polynomial coefficients.
- Divide by a generator polynomial to get parity bytes.
- Append parity to form each block’s full codeword set.
EC level determines parity amount:
- L (~7% recovery)
- M (~15%)
- Q (~25%)
- H (~30%)
4.5 Interleaving & Final Structure
Data is split into groups/blocks, RS-applied separately, then bytes are interleaved to spread risk of localized damage.
4.6 Masking & Penalty Scores
Eight logical masks are tested to minimize patterns that hinder decoding. Penalties are given for long runs, 2×2 blocks, finder-like patterns, and poor dark/light balance.
4.7 Format & Version Information
- Format Info: 5 bits (EC level) + 3 bits (mask) encoded with BCH (15,5).
- Version Info: For versions ≥7: 6 bits version + 12 bits BCH.
5. Decoding Pipeline: How Scanners Read Them
- Locate finder patterns via image processing.
- Determine orientation & perspective using the finders.
- Sample the grid using timing patterns.
- Read format info → get mask & EC level.
- Unmask the data area.
- Extract codewords by zig-zag traversal.
- Split into blocks and run Reed–Solomon decoding.
- Concatenate data codewords, parse mode/length/payload.
- Reconstruct original text/binary per mode rules.
6. Versions, Sizes, and Capacities
Version numbers range from 1–40. The number of modules per side is:
modules = 21 + 4 × (version − 1)- Version 1 → 21×21 modules
- Version 40 → 177×177 modules
Approximate maximum capacities at Version 40 / Level L:
- Numeric: ~7,089 digits
- Alphanumeric: ~4,296 characters
- Binary (8-bit): ~2,953 bytes
- Kanji: ~1,817 characters
Most consumer codes use Versions 1–10 (≤57×57).
7. Error Correction Levels (L, M, Q, H)
| Level | Recovery Capacity* | Typical Use Cases |
|---|---|---|
| L | ~7% | Clean printing, plenty of space |
| M | ~15% | General-purpose marketing |
| Q | ~25% | Likely wear/overprint |
| H | ~30% | Logos in codes, harsh environments |
*Approximate percentage of codewords that can be restored. Higher EC means fewer data bytes and larger versions.
8. Variants & Related Standards
- Model 1 vs. Model 2: Model 2 is prevalent; adds capacity and alignment patterns.
- Micro QR: Tiny (M1–M4) for very small items; only one finder pattern.
- iQR Code (Denso Wave): Rectangular options, higher capacities, 3–30% EC.
- FrameQR: Decorative frames with logos/pictures.
- SQRC: “Secure QR Code” with encrypted segments.
- JIS X 0510: Japanese standard.
- ISO/IEC 18004: International specification (revisions in 2015, 2024).
- Alternatives: Data Matrix, Aztec, PDF417, MaxiCode, etc.
9. Common & Creative Uses
- URLs & Marketing: Bridge print to web; track with UTM parameters.
- Payments & FinTech: Alipay, Paytm, PIX (Brazil), UPI (India), SEPA QR (EU).
- Authentication & 2FA: TOTP provisioning, device login handshakes.
- Logistics & Manufacturing: Traceability, parts tracking, warranty labels.
- Tickets & Boarding Passes: Offline validation at gates.
- Wi‑Fi Sharing: SSID + password embedding.
- Crypto & Wallets: Payment requests and addresses.
- Digital Menus & Forms: Contactless ordering/check-ins.
- AR/VR & IoT: Onboarding devices, context triggers.
- Education & Museums: Link to multimedia or extended info.
- Healthcare: Samples, patient IDs, e-prescriptions.
- Smart Packaging: Nutrition, provenance, recycling info.
- Government & Public Health: Check-ins, certificates, tax invoices.
10. Designing Better QR Experiences
- Provide context: e.g., “Scan to …”.
- Include a short URL fallback for non-camera users.
- Mind contrast & size: High contrast; ~1″ (2.5 cm) minimum for print. Rule: size ≈ scan distance / 10.
- Quiet zone: Leave ≥4 modules of white space.
- Test broadly: Different devices, lighting, print materials.
- Avoid busy backgrounds and low-contrast colors.
- Dynamic vs. static: Use dynamic if you need analytics or redirection later.
- Accessibility: Provide alt text and non-QR alternatives.
11. Security, Privacy & Risks
- Phishing & Malware: Hidden malicious URLs.
- QRjacking / Quishing: Attackers overlay fake codes on real posters.
- Data Harvesting: Tracking parameters log user info.
- Plaintext Secrets: Printed Wi‑Fi passwords or API keys can be scraped.
- Mitigations: Verify domains, educate users, sign payloads (JWS), expire sensitive data.
12. FAQs
13. Glossary
- Module
- A single black/white square in the QR grid.
- Version
- Determines dimensions (modules per side).
- Codeword
- 8-bit chunk of data or error correction bytes.
- Mask Pattern
- Binary pattern XOR’d with data modules to reduce visual artifacts.
- BCH Code
- Error-correcting code used for format/version info.
- Reed–Solomon
- Finite-field error correction used for data area.
- Quiet Zone
- White-space margin around the code.
- ECI
- Extended Channel Interpretation (character set info).
14. Further Reading & Standards Numbers
- ISO/IEC 18004: International QR Code standard.
- JIS X 0510: Japanese Industrial Standard for QR.
- Denso Wave’s official site & technical guides.
- Reed–Solomon & BCH academic papers for deeper math.
- Open-source libs: ZXing, ZBar, qrcode.js, pyqrcode, qrencode.
15. Appendix A: Pseudocode for a Minimal Encoder
function encode_qr(data, ec_level):
mode = choose_mode(data)
version = smallest_version_that_fits(data, mode, ec_level)
bitstream = []
bitstream.append(mode_indicator(mode))
bitstream.append(char_count_indicator(len(data), mode, version))
bitstream.append(encode_data_bits(data, mode))
bitstream = pad_to_codewords(bitstream, version, ec_level)
blocks = split_into_blocks(bitstream, version, ec_level)
for block in blocks:
block.ec = reed_solomon(block.data)
interleaved = interleave(blocks)
matrix = place_bits(interleaved, version)
best_mask = argmin(mask_patterns, penalty_score(mask(matrix)))
matrix = apply_mask(matrix, best_mask)
insert_format_info(matrix, ec_level, best_mask)
if version >= 7:
insert_version_info(matrix, version)
return matrix
16. Appendix B: Mask Pattern Formulas
Let r = row index, c = column index (0-based). Data modules are XOR’d with 1 if the expression is true.
- (r + c) mod 2 == 0
- r mod 2 == 0
- c mod 3 == 0
- (r + c) mod 3 == 0
- ((r div 2) + (c div 3)) mod 2 == 0
- ((r * c) mod 2) + ((r * c) mod 3) == 0
- (((r * c) mod 2) + ((r * c) mod 3)) mod 2 == 0
- (((r + c) mod 2) + ((r * c) mod 3)) mod 2 == 0
Penalty rules score:
- Runs of ≥5 same-colored modules
- 2×2 blocks of same color
- Finder-like 1:1:3:1:1 patterns
- Overall dark/light balance (target ~50%)
16. Developer API
text
You can pass a ?text= GET parameter to automagtically load a text string in the tool.
full
Passing a &full parameter will show the QR in full screen
qrStrokeColor / qrBgColor
Stroke and background colors of the QR code in hexadecimal, without the # symbol. Example: ff0000