Im ersten Teil dieser Beitragsreihe haben wir bereits den Ausdruck codiert, der später in Form eines QR-Codes grafisch abgebildet werden soll. Der weitaus interessantere Teil folgt noch: Die Berechnung des Fehlerkorrekturcodes. Schließlich folgt dann im letzten Teil der Beitragsreihe noch die Erstellung der eigentlichen Grafik, die Sie dann beispielsweise als Bilddatei speichern und etwa in einem Bericht einer Access-Datenbank weiterverwenden können.
Der Stand nach dem ersten Teil der Beitragsreihe ist, dass wir eine codierte Zeichenkette vorliegen haben – unabhängig davon, ob diese als Zahl, als reiner Text oder als alphanumerische Zeichenkette daherkommt. Außerdem haben wir eine Möglichkeit geschaffen, den Grad der Fehlerkorrektur auszuwählen und die Version, also die Kantenlänge des zu erzeugenden QR-Codes. Dieser wird schließlich bereits aus der Länge der zu kodierenden Zeichenkette, dem Fehlerkorrekturgrad und der Codiermethode ermittelt.
Als Nächstes benötigen wir den Fehlerkorrekturcode. Um diesen zu ermitteln, legen wir zunächst die Länge des Fehlerkorrekturcodes fest. Dies geschieht mithilfe einer Tabelle namens tblNumberOfDataCodewords (Entwurf siehe Bild 1). Die Tabelle liefert die folgenden wichtigen Informationen, wobei wir den Datensatz aus der Tabelle nutzen, dessen Felder VersionID und ErrorCorrectionLevelID für unsere Codierung zutreffen (s. Bild 2):
Bild 1: Entwurf der Tabelle tblVersions
Bild 2: Die Tabelle tblVersions mit einigen Werten
- Wir teilen den Code für unseren Text in ein, zwei oder vier Blöcken mit einer bestimmten Anzahl von Codewörtern mit je acht binären Zeichen auf. Wenn NumberOfBlocksInGroup1 den Wert 1 enthält, verwenden wir nur einen Block, der die im Feld NumberOfDataCodewordsInGroup1Blocks angegebene Anzahl von Codewörtern enthält.
- Wenn NumberOfBlocksInGroup1 den Wert 2 oder einen größeren Wert enthält, benötigen wir zwei oder mehr Blöcke mit der entsprechenden Anzahl von Codewörtern in der ersten Gruppe.
- Es gibt noch eine zweite Gruppe, für welche die beiden Felder NumberOfBlocksInGroup2 und NumberOfDataCodewordsInGroup1Blocks die Anzahl der Blöcke und Codewörter angeben.
Wenn wir also beispielsweise für VersionID den Wert 5 und für die Fehlerkorrektur den Level Q ausgewählt haben, haben wir zwei Gruppen, wobei die erste zwei Blöcke mit je 15 Codewörtern aufnimmt und die zweite zwei Blöcke mit je 16 Codewörtern. Wenn Sie also beispielsweise einen Text codieren, der mit den oben genannten Parametern um einen Fehlerkorrekturcode erweitert werden soll, wird dieser Text 2 x 15 x 8 + 2 x 16 x 8 Zeichen lang sein, also 496 Zeichen lang sein – was auch der Fall ist. Wir brechen dies auf ein einfacheres Beispiel herunter, zum Beispiel zur Codierung der Zeichenkette HELLO WORLD. Wir verwenden den Fehlerkorrekturgrad M und die kleinste Version mit 21 x 21 Zeichen. Die codierte Zeichenfolge sieht nach der Beschreibung aus dem ersten Teil der Beitragsreihe so aus:
0010000001011011000010110111100011010001011100101101110001001101
0100001101000000111011000001000111101100000100011110110000010001
Die Tabelle tblNumberOfDataCodewords liefert die Information, dass diese Zeichenfolge in eine Gruppe mit 16 Blöcken á acht Zeichen aufgeteilt wird, also etwa so:
- 00100000
- 01011011
- 00001011
- …
Diese Zahlen benötigen wir später, wenn wir ein Polynom für den zu codierenden Text erstellen müssen. Die Zahlen dienen dann als Koeffizienten.
Steuerung der Codierung
Die Codierung starten Sie mit einem Klick auf die Schaltfläche cmdAktualisieren des Formulars frmQRCodes, das nun wie in Bild 3 aussieht. Dieses Formular erlaubt, wie schon im ersten Teil erläutert, die Eingabe des zu codierenden Textes in das Textfeld txtAusgangstext, die Auswahl des Zeichensatzes mit dem Kombinationsfeld cboModeID, den Grad der Fehlerkorrektur mit cboErrorCorrectionID und die Version beziehungsweise Kantenlänge mit cboVersionID.
Bild 3: Das Formular frmQRCodes
Die Schaltfläche cmdAktualisieren löst nun die Prozedur aus Listing 1 aus. Diese erledigt zunächst die bereits im ersten Teil der Beitragsreihe beschriebenen Aufgaben, sprich: den binären Code zu ermitteln, welcher die Information über die Codierung, die Anzahl der Zeichen und den Text selbst in binärer Form enthält.
Private Sub cmdAktualisieren_Click() Dim strCode As String Dim lngBlocksGruppe1 As Long Dim lngWoerterGruppe1 As Long Dim lngBlocksGruppe2 As Long Dim lngWoerterGruppe2 As Long Dim lngVersionID As Long Dim lngErrorCorrectionLevelID As Long Dim db As DAO.Database Dim rst As DAO.Recordset Dim intAnzahlFehlerkorrekturWoerter As Integer Set db = CurrentDb strCode = strCode & GetModeIndicator strCode = strCode & GetCharacterCountIndicator strCode = strCode & Encode(Me!txtAusgangstext, Me!cboModeID) strCode = AddPadBytes(strCode, Me!cboVersionID, Me!cboErrorCorrectionID) Me!txtCodeInhalt = strCode lngVersionID = Me!cboVersionID lngErrorCorrectionLevelID = Me!cboErrorCorrectionID Set rst = db.OpenRecordset("SELECT * FROM tblNumberOfDataCodewords " _ & "WHERE VersionID = " & lngVersionID _ & " AND ErrorCorrectionLevelID = " & lngErrorCorrectionLevelID) lngBlocksGruppe1 = rst!NumberOfBlocksInGroup1 lngWoerterGruppe1 = rst!NumberOfDataCodewordsInGroup1Blocks lngBlocksGruppe2 = Nz(rst!NumberOfBlocksInGroup2, 0) lngWoerterGruppe2 = Nz(rst!NumberOfDataCodewordsInGroup2Blocks, 0) intAnzahlFehlerkorrekturWoerter = rst!ECCodewordsPerBlock Me!txtInterleavedCode = InterleavedCode(strCode, lngBlocksGruppe1, lngWoerterGruppe1, _ lngBlocksGruppe2, lngWoerterGruppe2) Me!txtInterleavedErrorCorrectionCode = InterleavedErrorCode(strCode, lngBlocksGruppe1, _ lngWoerterGruppe1, lngBlocksGruppe2, lngWoerterGruppe2, intAnzahlFehlerkorrekturWoerter) Me!txtQRCode = Me!txtInterleavedCode & Me!txtInterleavedErrorCorrectionCode End Sub
Listing 1: Diese Prozedur steuert die komplette Codierung.
Dann speichert die Prozedur die Werte der beiden Kombinationsfelder cboVersionID und cboErrorCorrectionID in entsprechenden Variablen, bevor sie darauf basierend ein Recordset öffnet. Dieses enthält den Datensatz der Tabelle tblNumberOfDataCodewords, der den mit den Kombinationsfeldern ausgewählten Parametern entspricht. Aus dieser Tabelle entnehmen wir einige Werte und speichern diese in weiteren Variablen:
- lngBlocksGruppe1
- lngWoerterGruppe1
- lngBlocksGruppe2
- lngWoerterGruppe2
- intAnzahlFehlerkorrekturWoerter
Nun folgt der interessante, in diesem Teil der Beitragsreihe beschriebene Part: Die Umwandlung des binären Codes in einen sogenannten “interleaved” Code und das Ermitteln und Hinzufügen des Fehlerkorrekturcodes.
Dies geschieht in folgenden Schritten:
- Vermischen des Codes zum “interleaved” Code mit der Funktion InterleavedCode,
- Ermitteln des Fehlerkorrekturcodes auf Basis des Ausgangscodes und Vermischen zum “interleaved” Fehlerkorrekturcode mit der Funktion InterleavedErrorCode und
- Zusammenfügen der beiden Teile im Textfeld txtQRCode.
Schauen wir uns nun an, wie diese Funktionen arbeiten.
Code weiter bearbeiten
Den Code aus dem Textfeld txtCodeInhalt beziehungsweise der Variablen strCode verwenden wir nun nicht einfach so als ersten Teil des QR-Codes. Stattdessen wird dieser erste Teil gegebenenfalls noch etwas durcheinandergewürfelt – allerdings nach fest vorgegebenen Regeln. Dies geschieht allerdings nur ab einer gewissen Länge des Codes beziehungsweise wenn die einzelnen achtstelligen Binärzahlen auf mehr als nur die erste Gruppe aufgeteilt werden – also wenn in der Tabelle tbl-NumberOfDataCodewords in der Spalte für die aktuelle Konfiguration (aus Version und Fehlerkorrektur) auch ein Wert in den Spalten NumberOfBlocksInGroup2 beziehungsweise NumberOfDataCodewordsInGroup2Blocks vorliegen. Dies ist zum Beispiel der Fall, wenn Sie die Version 5 (37 x 37 Pixel) und den Fehlerkorrekturgrad Q wählen. Dieser Code hat insgesamt 62 Codewörter, wobei die erste Gruppe zwei Blocks mit je 15 Codewörtern enthält und die zweite Gruppe zwei Blocks mit je 16 Codewörtern. Die Prozedur InterleavedCode aus Listing 2 erwartet drei Parameter:
Public Function InterleavedCode(ByVal strCode As String, lngBlocksGruppe1 As Long, _ lngWoerterGruppe1 As Long, lngBlocksGruppe2 As Long, lngWoerterGruppe2 As Long) Dim i As Integer Dim j As Integer Dim strTempNeu As String Dim strTemp As String Dim intCodewoerterMatrix() As Integer intCodewoerterMatrix = CodeWoerterMatrix(lngBlocksGruppe1, lngWoerterGruppe1, _ lngWoerterGruppe2, lngBlocksGruppe2) strTemp = Trim(strCode) If lngWoerterGruppe2 <> 0 Then For j = 1 To lngWoerterGruppe2 For i = 1 To lngBlocksGruppe1 + lngBlocksGruppe2 If intCodewoerterMatrix(i, j) <> 0 Then strTempNeu = strTempNeu + Mid$(strTemp, intCodewoerterMatrix(i, j) * 8 - 7, 8) End If Next i Next j End If If lngWoerterGruppe2 = 0 Then For j = 1 To lngWoerterGruppe1 For i = 1 To lngBlocksGruppe1 + lngBlocksGruppe2 If intCodewoerterMatrix(i, j) <> 0 Then strTempNeu = strTempNeu + Mid$(strTemp, intCodewoerterMatrix(i, j) * 8 - 7, 8) End If Next i Next j End If InterleavedCode = strTempNeu End Function