Een QR-code met de hand lezen

In deze handleiding leer je hoe je codeversies V1-V5 kunt lezen in de byte-coderingsmodus, inclusief alle Error-Correcting-Code (ECC) niveaus en maskeringspatronen. Op basis van een kleine willekeurige steekproef (n=1024) van QR-codes op het internet, betekent dit dat je ongeveer 80% van de QR-codes die je in de echte wereld tegenkomt, zult kunnen lezen. Het lezen van grotere codes of codes met een andere codering is niet moeilijker, maar vereist aanzienlijk meer inspanning en onthoudingsvermogen.

Wat heb je nodig?

  • Een QR-code die je wilt lezen. (Let op: deze handleiding gaat over QR-codes, niet over Aztec- of UPC-codes).
  • Tijd. Afhankelijk van de grootte, de payload en je bekendheid met ASCII-codering, zal het waarschijnlijk 10 tot 120 minuten duren.
  • Deze handleiding. Digitaal of geprint.

Voor wie nog niet weet hoe QR-codes intern werken, is het sterk aanbevolen om eerst de technische achtergrond te lezen voordat je aan de slag gaat.

De basis: Versies en formaten

QR-codes komen voor in 40 verschillende formaten (de grootte van het raster waarop de blokken staan, exclusief padding), ook wel versies genoemd. Je kunt de versie berekenen met de formule: versie = (grootte - 17) ÷ 4.

Deze handleiding richt zich op versies 1 tot en met 5:

  • Versie 1: 21 × 21
  • Versie 2: 25 × 25
  • Versie 3: 29 × 29
  • Versie 4: 33 × 33
  • Versie 5: 37 × 37

Stappenplan voor het lezen van de QR-code

Stap 1: De modules inkleuren

Kleur de QR-code modules in. Als een module slechts een diagonale lijn bevat, kleur dan alleen de linkerbovenhelft in. Focus hierbij op de modules die op de leeslijn liggen.

Stap 2: Data-digits invullen

Voor elk (interleaved) data-cijfer (4 opeenvolgende bits langs de leeslijn), vul je de waarde in de blokkentabel. Vierkanten met een diagonale lijn worden geïnterpreteerd als 'inverted'.

WaardeBinairWaardeBinair
0000081000
1000191001
20010A1010
30011B1011
40100C1100
50101D1101
60110E1110
70111F1111

Stap 3: De data decoderen

Lees de datablokken achter elkaar (concateneren).

  1. Coderingsmodus: Het eerste cijfer geeft de modus aan: 1 voor numeriek, 2 voor alphanumeric, 4 voor byte. Deze handleiding werkt alleen voor byte-modus.
  2. Lengte: De volgende twee cijfers representeren het aantal tekens dat gelezen moet worden.
  3. ASCII-waarden: Daarna vormen elke twee cijfers samen een getal van 0 tot 255, wat de ASCII-waarde representeert.

Handige ASCII-referenties:

  • 31 (hex) is '1'
  • 41 is 'A'
  • 61 is 'a'
  • 2E is '.'
  • 2F is '/'
  • 3A is ':'

---

Gedetailleerde technische uitleg: Hoe worden QR-codes gegenereerd?

Om een QR-code handmatig te kunnen lezen, is het essentieel om te begrijpen hoe ze worden gemaakt. Hier zijn de vereenvoudigde stappen van het generatieproces:

1. Datacodering

De data (meestal tekst) wordt omgezet in een bitstroom (0en en 1en). De meeste codes (ca. 90%) gebruiken de byte-modus, die het makkelijkst te decoderen is en Latijnse letters, cijfers en veel speciale tekens ondersteunt.

2. Lengte en modus toevoegen

Aan het begin van de bitstroom wordt de coderingsmodus en het aantal tekens toegevoegd. Voor byte-modus in versies 1-5 wordt de lengte altijd gecodeerd in 8 bits (één byte).

3. ECC-niveau kiezen

Er wordt een Error-Correcting-Code (ECC) niveau gekozen om fouten te kunnen herstellen (gebaseerd op Reed-Solomon met GF(256)). De beschikbare niveaus zijn:

  • L (Low)
  • M (Medium)
  • Q (Quartile)
  • H (High)

Dit niveau bepaalt hoeveel ECC-codewoorden worden toegevoegd en in hoeveel blokken de data wordt gesplitst.

4. Versie bepalen

Er wordt een versie (1-40) gekozen die past bij de hoeveelheid data. De grootte wordt berekend als size = versie * 4 + 17. De kleinste QR-code (V1) kan 26 bytes bevatten, waarvan er minstens 9 data zijn.

5. Data splitsen in blokken

Afhankelijk van de versie en het ECC-niveau wordt de data verdeeld over verschillende blokken.

Aantal blokken per versie en ECC-niveau:

VersieLMQH
V11916139
V234282216
V3554417+1713+13
V48032+3224+249+9+9+9
V510843+4315+15+16+1611+11+12+12

6. Interleaving

De blokken worden 'interleaved' (om en om afgewisseld) om één continue bitstroom te vormen. Dit zorgt ervoor dat regionale schade aan de code wordt verspreid over verschillende ECC-blokken, wat het herstel vergemakkeligt.

7. Layout en plaatsing

De data wordt in het raster geplaatst volgens een vast patroon:

  1. Eerst worden de finder patterns (de grote vierkanten) en timing patterns getekend.
  2. Vervolgens worden de ECC- en maskeringsinformatie rond de ogen geplaatst.
  3. De bit-data wordt in de overgebleven ruimte geplaatst volgens een zig-zag lijn.
  4. Eventuele lege ruimte wordt opgevuld met een terminator (0000) en padding bytes (EC 11 EC 11).

8. Maskeringspatroon

Om te voorkomen dat er patronen ontstaan die lijken op de timing patterns, wordt een maskeringspatroon over de data en ECC-bytes gelegd. Er zijn acht mogelijke patronen. Elke module die door het patroon wordt geraakt, wordt geïnverteerd via een XOR-operatie.

Maskeringspatronen en hun formules:

PatroonFormule
0(x + y) % 2 === 0
1y % 2 === 0
2x % 3 === 0
3(x + y) % 3 === 0
4(floor(y / 2) + floor(x / 3)) % 2 === 0
5(((x y) % 2) + ((x y) % 3)) === 0
6((((x y) % 2) + ((x y) % 3)) % 2) === 0
7((((x + y) % 2) + ((x * y) % 3)) % 2) === 0

---

Handmatig een QR-code tekenen

Het is theoretisch mogelijk, maar wordt in deze handleiding niet behandeld. De reden is dat het berekenen van de Reed-Solomon ECC-waarden handmatig duizenden XOR-operaties vereist, wat extreem tijdrovend en foutgevoelig is.

---

Toepassing van de kennis via het werkblad

Om een code te lezen, keren we het generatieproces om:

  1. Metadata bepalen: Bereken de versie op basis van de grootte. Lees de eerste 5 bits onder het linkerbovenste zoeker-patroon. De eerste twee bits bepalen het ECC-niveau (00 → H, 10 → M, 01 → Q, 11 → L). De volgende drie bits bepalen het maskeringspatroon. Let op: deze bits zijn zelf gemaskeerd met het patroon 101 (flip de eerste en derde bit).
  2. Data kopiëren: Kopieer de raw data-bits zonder het maskeringspatroon.
  3. De-interleaving: Lees de data langs de groene lijn en vul de blokken in. Doe dit byte-voor-byte (twee digits per keer): vul eerst het eerste byte van blok 1, dan blok 2, enzovoort, voordat je terugkeert naar het tweede byte van blok 1.
  4. ASCII-decodering: Zet de bitstroom om naar ASCII. Begin met de modus (hopelijk 0100 voor byte-modus), bepaal de lengte, en vertaal vervolgens de bytes naar tekens aan de hand van de ASCII-tabel.

ASCII Referentietabel:

HexTekens
2xspace ! " # $ % & ' ( ) * + , - . /
3x0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4x@ A B C D E F G H I J K L M N O
5xP Q R S T U V W X Y Z [ \ ] ^ _
6x` a b c d e f g h i j k l m n o ``
7x`p q r s t u v w x y z {} ~`

(Opmerking: Entries beginnend met 0, 1, 8-F worden gebruikt voor controle-sequenties of UTF-codering en worden in deze basismethode genegeerd).

---

Analyse van willekeurige QR-codes

Om te bepalen welke parameters optimaal zijn voor deze handleiding, is er een analyse uitgevoerd op 1024 willekeurige QR-codes van Flickr (via Openverse). De zoekopdrachten bestonden uit diverse termen in verschillende talen (waaronder Engels, Chinees, Japans, Spaans, Frans, Russisch en Duits) gerelateerd aan QR-advertenties, menu's, tickets en zakelijke kaarten.

Uit deze analyse bleek dat QR-codes met een enkel segment, versie V1-V5 en byte-modus codering, verantwoordelijk zijn voor 79,8% van de steekproef. Dit bevestigt dat deze methode bruikbaar is voor de overgrote meerderheid van de QR-codes in de praktijk.

***

Auteur: Noel Friedrich Datum: 21.06.2026