-
Notifications
You must be signed in to change notification settings - Fork 71
/
BARCODER.ahk
1761 lines (1559 loc) · 116 KB
/
BARCODER.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;############################################################################################################
; Barcode Generator Library v1.02 by Giordanno Sperotto.
; Updated: 27 December 2014.
; General Notes for this library (Refer to functions GENERATE_QR_CODE(), GENERATE_CODE_39(), GENERATE_CODE_ITF() and GENERATE_CODE_128B()
; for specific operating instructions).
;
; Barcode Generator Library v1.01 by Giordanno Sperotto is an AutoHotkey (AHK) library designed to help generate Barcodes for
; AHK applications.
;
; Barcodes are usually used as a mean to store logistical data in the physical bodys of products and packages, so as to better allow
; managing of lot numbers, expiring dates and other specific aspects of these products. QR Codes, a type of Two-Dimensional (2D)
; Barcodes, have also been used a marketing tool to quickly guide customers to website stores and ease up the sales of their products.
; The use of barcodes, however, is not restricited to such cases and careful thought over how to use a quick and cheap way of
; printing and reading data from physical objects should definitely sparkle some new interesting ideas for a programmer.
;
; Best wishes.
;
; List of Main functions:
; GENERATE_QR_CODE() -> Call this function to retrieve a table object (2D) that represents the dark and light pixels of a QR Code
; Matrix by their respective addresses.
; GENERATE_CODE_39() -> Call this functions to retrieve an object that represents the dark and light pixels of a CODE39
; row by their respective addresses (Note: Even tough the code is 1D, the image to be printed is actually 2D, so stack as many copies
; of the single line over each other for the height of the image you wish to create).
; GENERATE_CODE_ITF() -> Call this function to retrieve an object that represents the monochrome dark and light pixels of an Interleaved
; Code 2 of 5 row. (Note: Even tough the code is 1D, the image to be printed is actually 2D, so stack as many copies
; of the single line over each other for the height of the image you wish to create).
; GENERATE_CODE_128B() -> Call this functions to retrieve an object that represents the dark and light pixels of a CODE128B
; row by their respective addresses (Note: Even tough the code is 1D, the image to be printed is actually 2D, so stack as many copies
; of the single line over each other for the height of the image you wish to create).
;##############################################################################################################
;##############################################################################################################
; QR Code Functions v1.02
; General Notes from the author (refer to the function "GENERATE_QR_CODE()" for an explanation on how to create a QR Code Matrix):
;
; QR Codes (a type of 2D barcode) are a great tool to print to and recover data from physical objects. An advancement compared
; to regular 1D barcodes, they can contain more data (Up to 7,089 numeric characters for v40), encode bigger sets of characters, are
; more reliable than the previous and can be read quite quick with current market level hardware/software. Most 2D readers currently available
; will ship bundled with reader software and will simply autotype the decoded message to the selected field of your application. Also, there is
; probably an application to read QR Codes available for use with your very own cell phone as of today.
;
; For logistical purposes, you can simply print a QR Code on a label and stick it to an object you wish to track, and you (or another person) will
; be able to recover the data stored inside the image at a later time. This ensures a whole new world of possibilities for industrial and commercial
; processes.
;
; If you are seeking out how QR Codes work, the full form of implementing them is described in the document for ISO 18004. The code for this
; implementation has also been commented whenever i felt like something needed an explanation, but this is NOT a tutorial.Thonky has an
; online tutorial for generating QR Codes, which has greatly helped this implementation. You can check it out on http://www.thonky.com/qr-code-tutorial/
;
; Thanks to tic (Tariq Porter) for his GDI+ Library (http://www.autohotkey.com/forum/viewtopic.php?t=32238), which has been used through the
; development of this library to display the images of the QR Matrixes.
;
; Thanks to Infogulch for the functions Bin() and Dec() (http://www.autohotkey.com/board/topic/49990-binary-and-decimal-conversion/).
;
; Thanks to AlphaBravo for the functions GENERATE_CODE_ITF(), Add_Check_Sum() and GENERATE_CODE_128B()
; (http://ahkscript.org/boards/viewtopic.php?f=6&t=5538&p=32299#p32299)
; (https://autohotkey.com/boards/viewtopic.php?p=93223#p93223)
;
; "QR Code" is a registered trademark of DENSO-WAVE (http://www.qrcode.com/en/faq.html) and the specifications of the standard are
; publicly available. You are free to use QR Codes on commercial applications and no contracts/fees are required, but you may have to
; credit Denso-Wave if you explicitly refer to the name "QR Code".
;
; Best wishes.
;CHANGELOG:
;11 December 2014: First version is up. Supports CODE39 and QR Code barcode generation. Examples added to the post.
;23 December 2014: Added Interleaved 2 of 5 Functions by AlphaBravo. Changed the lib and function names to allow MyLib_MyFunc syntax compatibility.
;25 December 2014: Fixed a typo in the code generating incorrect version 11-M matrixes.
;27 December 2014: Ran a test on each of the 40 QR Code versions, using each of the 4 ECLs for every version. All 160 matrixes generated were found to be readable. Changed Version to 1.01 to avoid confusion with non-working version 11 scripts.
; 23 June 2016: Added Code128B generating functions designed by AlphaBravo.
;##############################################################################################################
;##################################################################################################################################################################
; GENERATE_QR_CODE() v1.01 by Giordanno Sperotto.
; How to generate QR Codes using this library:
; This function takes four parameters.
;
; The First parameter is the message to encode. Please make sure that the message contains only ASCII characters (for this
; version of the library).
;
; The Second parameter is the Code Mode to be applied, which can be 0 (Automatic choosing - Default and recommended), 1 (Numeric, can only encode sequences of
; numeric characters, with no commas, dots or any other symbols), 2 (AlphaNumeric, can only encode sequences of numeric characters, UPPERCASE letters A-Z and symbols
; $, %, *, +, -, ., /, :, and \.), and finally 3 (Byte, which can encode any type of ASCII character, but usually requires a higher version QR Code for the same length of the string compared to the other two.
; The function will abort execution and display a message if you try to Force the encoding of a message in a Code Mode that cannot contain all the characters entered.
;
; The Third parameter is the CHOOSEN_ERROR_CORRECTION_LEVEL. QR Code matrixes are able to output the correct message even if they are damaged (to some extent and excluding some critical
; areas). As the choosen Error Correction Level increases, this power improves, but the output matrix becomes bigger, requiring a bigger version to encode the same ammount of data. Available Error
; Correction Levels are 1 (Level L, can recover the full data if only up to 7% of the codewords are damaged but will create the smallest matrix outputs, 2 (Level M, the default level, can recover the full data
; if up to 15% of the codewords are damaged), 3 (Level Q, can recover the full data if up to 25% of the codewords are damaged) and 4 (Level H, can recover the full data if up to 30% of the codewords are
; damaged - This level has the lowest available space for message codewords in each version).
;
; The Fourth parameter is the CHOOSEN_VERSION. It defaults to 0 (Automatic, Best) which will use the smallest version that can hold the entire message. Although it is possible to use a bigger version
; to encode a small message, this is not a good idea, as it will increase the resources required to generate and decode the matrix, aswell as increase the possibility of a false reading (The latter should
; only be of real concern if the reader hardware/software is scanning the message for other types of 2D barcodes aswell, as QR Codes have a very low false positive possibility (lower than 1D barcodes AFAIK),
; but don't really check for the existence of a submatrix that conforms to the other available standards (in example: they may contain a valid small Data Matrix.)). Either way, the lowest version that can encode
; the entire message is the recomended version here, and the default value for this parameter (0) will find that version for you. The function will abort execution and display a message if you try to Force the
; encoding of a message in a QR Code Version that cannot contain all the characters entered.
;
; HOW TO INTERPRET THE RESULTS:
; If the call is succesfull, the function returns a 2D object, which should be interpreted as MATRIX_TO_PRINT[ROW ADDRESS, COLUMN ADDRESS], where each possible values for Row and Column addresses will reffer to a single module
; (black or white square) inside the matrix. You can thus easily access the individual modules of the output matrix one by one with a loop inside a loop, both set to iterate up to the MaxIndex() of the object.
; After this, you can use any type of image library you like to create the images, save to disk, print or display in a GUI. I recommend you to use GDI+ Library by Tic.
; (http://www.autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic). Do not forget to include reasonable sized "quiet zones" (light colored areas) surrouding the output QR Code image for better readability.
; Example:
;
; Loop % Object.MaxIndex()
; {
; ROW := A_Index
; Loop % Object[1].MaxIndex()
; {
; COLUMN := A_Index
; CURRENT_VALUE := Object[ROW, COLUMN]
; If (CURRENT_VALUE = 1)
; {
; msgbox % "The pixel in row " . ROW . " and column " . COLUMN . " is dark.
; }
; Else
; msgbox % "The pixel in row " . ROW . " and column " . COLUMN . " is light.
; }
;}
;
; Other possible return values (Error values)
; 1 - Input message is blank.
; 2 - Forced Code Mode cannot encode all the characters in the input message.
; 3 - Choosen Code Mode does not correspond to one of the currently indexed code modes (Automatic, numeric, alphanumeric or byte).
; 4 - The choosen forced version cannot encode the entire input message using the choosen ECL Code_Mode. Try forcing a higher version or choosing automated version selection (parameter value 0).
; 5 - The input message is exceeding the QR Code standards maximum length for the choosen ECL and Code Mode.
; 6 - Choosen Error Correction Level does not correspond to one of the standard ECLs (L, M, Q and H).
; 7 - Forced version does not correspond to one of the QR Code standards versions.
;###################################################################################################################################################################
BARCODER_GENERATE_QR_CODE(MESSAGE_TO_ENCODE, CHOOSEN_CODE_MODE := 0, CHOOSEN_ERROR_CORRECTION_LEVEL := 2, CHOOSEN_VERSION := 0)
{
Global
MATRIX_TO_PRINT := ""
CREATE_LOG_AND_ANTILOG_TABLES()
LIST_NUMBER_OF_GROUPS_AND_BLOCKS() ; Necessary for processing the later step of interleaving of CodeWords (CW) and ErrorCorrectionWords (ECW).
GENERATE_ALPHANUMERIC_TABLE()
GENERATE_VERSION_CAPACITY_CUBE()
If (MESSAGE_TO_ENCODE = "")
{
Return 1 ; Input message is blank.
}
; The best Code Mode is the one that succesfully encodes the entire message, but outputs the smaller QR Matrix. Numeric should be used whenever possible, AlphaNumeric is the second best choice and Byte mode should be selected only if the message cannot be encoded using the other two. Numeric can only hold numbers (sequences of the characters 0-9), AlphaNumeric can only hold numbers, uppercase letters A-Z and the symbols $, %, *, +, -, ., /, :, and \. Byte Mode can hold the entire ASCII table and Kanji mode can hold Japanese/Chinese/Korean characters.
if (CHOOSEN_CODE_MODE = 0)
{
if MESSAGE_TO_ENCODE is number
{
CHOOSEN_CODE_MODE := 1
}
Else If (RegExMatch(MESSAGE_TO_ENCODE, "[^A-Z0-9`$`%`*`+`-`.`/`:`\ ]") = 0)
{
CHOOSEN_CODE_MODE := 2
}
Else
{
CHOOSEN_CODE_MODE := 3
}
}
If !((CHOOSEN_VERSION >= 0) AND (CHOOSEN_VERSION <= 40))
{
; Msgbox, 0x10, Error, Forced Version does not correspond to one of the QR Code standards versions. Please choose a version from 1 to 40. You can also specify 0 to let the function choose the best one for you.
Return 7 ; Forced version does not correspond to one of the QR Code standards versions.
}
; The best version to use is the smallest that sucessfully encodes the entire message.
If (CHOOSEN_VERSION = 0)
{
Loop 40
{
If (StrLen(MESSAGE_TO_ENCODE) <= CAPACITY_CUBE[A_Index, CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_CODE_MODE])
{
CHOOSEN_VERSION := A_Index
Break
}
}
CODE_MODE_TO_USE := ""
}
If (CHOOSEN_VERSION = 0) ; If the conditionals above failed to find a suitable version...
{
Return 5 ; The input message is exceeding the QR Code standards maximum length for the choosen ECL and Code Mode.
}
if ((CHOOSEN_CODE_MODE != 1) AND (CHOOSEN_CODE_MODE != 2) AND (CHOOSEN_CODE_MODE != 3) AND (CHOOSEN_CODE_MODE != 0))
{
;msgbox, 0x10, Error, Please select an appropriate code mode for the message.
Return 3 ; Choosen Code Mode does not correspond to one of the currently indexed code modes (Automatic, numeric, alphanumeric or byte).
}
if ((CHOOSEN_ERROR_CORRECTION_LEVEL != 1) AND (CHOOSEN_ERROR_CORRECTION_LEVEL != 2) AND (CHOOSEN_ERROR_CORRECTION_LEVEL != 3) AND (CHOOSEN_ERROR_CORRECTION_LEVEL != 4))
{
;msgbox, 0x10, Error, Please select an appropriate code mode for the message.
Return 6 ; Choosen Error Correction Level does not correspond to one of the standard ECLs (L, M, Q and H).
}
If !(StrLen(MESSAGE_TO_ENCODE) <= CAPACITY_CUBE[CHOOSEN_VERSION, CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_CODE_MODE])
{
Return 4 ; The choosen forced version cannot encode the entire input message using the choosen ECL Code_Mode.
}
if (CHOOSEN_CODE_MODE = 1)
{
if MESSAGE_TO_ENCODE is not number
{
;msgbox, 0x10, Error, Numeric code mode can only encode the characters 0-9. Please correct the Message to Encode or change the selected Code Mode if you wish to encode other characters.
Return 2 ; Forced Code Mode cannot encode all the characters in the input message.
}
Numeric_Mode := "0001" ; Numeric type
If (CHOOSEN_VERSION <= 9)
{
Char_Count := SubStr("0000000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -9, 10) ; 10 bits with the size of the string are req for V1-9 Numeric.
}
If (CHOOSEN_VERSION >= 10) AND (CHOOSEN_VERSION <= 26)
{
Char_Count := SubStr("000000000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -11, 12) ; 12 bits with the size of the string are req for V10-26 Numeric.
}
If (CHOOSEN_VERSION >= 27) AND (CHOOSEN_VERSION <= 40)
{
Char_Count := SubStr("00000000000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -13, 14) ; 14 bits with the size of the string are req for V27-40 Numeric.
}
MESSAGE_CODE := Numeric_Mode . Char_Count ; We will add the codewords in the function call bellow, so "Message_Code" is not really complete here.
MESSAGE_STRING := CONVERT_TO_NUMERIC_ENCODING(MESSAGE_TO_ENCODE)
}
if (CHOOSEN_CODE_MODE = 2)
{
If !(RegExMatch(MESSAGE_TO_ENCODE, "[^A-Z0-9`$`%`*`+`-`.`/`:`\ ]") = 0)
{
;msgbox, 0x10, Error, AlphaNumeric Code Mode can only encode numeric characters, letters from A to Z (uppercase only), whitespaces and the symbols `$, `%, `*, `+, `-, `., `/ and `:. Please correct the Message to Encode or change the selected Code Mode if you wish to encode any other characters.
Return 2 ; Forced Code Mode cannot encode all the characters in the input message.
}
ALPHANUMERIC_MODE := "0010"
If (CHOOSEN_VERSION <= 9)
{
Char_Count := SubStr("000000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -8, 9) ; 9 bits with the size of the string are req for V1-9 AlphaNumeric.
}
If (CHOOSEN_VERSION >= 10) AND (CHOOSEN_VERSION <= 26)
{
Char_Count := SubStr("00000000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -10, 11) ; 11 bits with the size of the string are req for V10-26 AlphaNumeric.
}
If (CHOOSEN_VERSION >= 27) AND (CHOOSEN_VERSION <= 40)
{
Char_Count := SubStr("0000000000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -12, 13) ; 13 bits with the size of the string are req for V27-40 AlphaNumeric.
}
MESSAGE_CODE := ALPHANUMERIC_MODE . Char_Count ; We will add the codewords in the function call bellow, so "Message_Code" is not really complete here.
MESSAGE_STRING := CONVERT_TO_ALPHANUMERIC_ENCODING(MESSAGE_TO_ENCODE)
}
if (CHOOSEN_CODE_MODE = 3)
{
BYTE_MODE := "0100"
If (CHOOSEN_VERSION <= 9)
{
Char_Count := SubStr("00000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -7, 8) ; 8 bits with the size of the string are req for V1-9 Byte Mode.
}
If (CHOOSEN_VERSION >= 10) AND (CHOOSEN_VERSION <= 40)
{
Char_Count := SubStr("0000000000000000" . Bin(StrLen(MESSAGE_TO_ENCODE)), -15, 16) ; 16 bits with the size of the string are req for V10-40 Byte Mode.
}
MESSAGE_CODE := BYTE_MODE . Char_Count ; We will add the codewords in the function call bellow, so "Message_Code" is not really complete here.
MESSAGE_STRING := CONVERT_TO_BYTE_ENCODING(MESSAGE_TO_ENCODE)
}
;To add the terminator, we have to know how many data codewords the version and ECL require. the V2H, in example, requires 16 data codewords, which equals 128 bits. If the string length up to now is less than that, we have to add the terminator, which is composed of up to 4 zeroed bits. The limit would than be 128, which means that if the string thus far is 127 bits, our terminator would be "0", if it were 126, "00", and so on up to "0000" which is the maximum for the terminator, in case the string were equal to or less than 124 bits. Once again: each version and ECL requires a different number of codewords to fill it's capacity, and we are creating a list for selecting these here.
TOTAL_CODEWORDS := Object()
TOTAL_CODEWORDS[1] := [19,34,55,80,108,136,156,194,232,274,324,370,428,461,523,589,647,721,795,861,932,1006,1094,1174,1276,1370,1468,1531,1631,1735,1843,1955,2071,2191,2306,2434,2566,2702,2812,2956] ; ECL L
TOTAL_CODEWORDS[2] := [16,28,44,64,86,108,124,154,182,216,254,290,334,365,415,453,507,563,627,669,714,782,860,914,1000,1062,1128,1193,1267,1373,1455,1541,1631,1725,1812,1914,1992,2102,2216,2334] ; ECL M
TOTAL_CODEWORDS[3] := [13,22,34,48,62,76,88,110,132,154,180,206,244,261,295,325,367,397,445,485,512,568,614,664,718,754,808,871,911,985,1033,1115,1171,1231,1286,1354,1426,1502,1582,1666] ; ECL Q
TOTAL_CODEWORDS[4] := [9,16,26,36,46,60,66,86,100,122,140,158,180,197,223,253,283,313,341,385,406,442,464,514,538,596,628,661,701,745,793,845,901,961,986,1054,1096,1142,1222,1276] ; ECL H
;128 bits are required for a V2H Mode + Char_Count + String + Terminator + Pads. The terminator contains at most 4 zeros (limited also to the max string size of 128 bits). The pads are sequences of the bytes "11101100" and "00010001" appended in alternating mode right after the terminator.
;125
If StrLen(MESSAGE_CODE . MESSAGE_STRING) < (TOTAL_CODEWORDS[CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_VERSION] * 8) - 3
{
MESSAGE_UP_TO_TERMINATOR := MESSAGE_CODE . MESSAGE_STRING . "0000"
}
Else if StrLen(MESSAGE_CODE . MESSAGE_STRING) < (TOTAL_CODEWORDS[CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_VERSION] * 8) - 2
{
MESSAGE_UP_TO_TERMINATOR := MESSAGE_CODE . MESSAGE_STRING . "000"
}
Else if StrLen(MESSAGE_CODE . MESSAGE_STRING) < (TOTAL_CODEWORDS[CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_VERSION] * 8) - 1
{
MESSAGE_UP_TO_TERMINATOR := MESSAGE_CODE . MESSAGE_STRING . "00"
}
Else if StrLen(MESSAGE_CODE . MESSAGE_STRING) < (TOTAL_CODEWORDS[CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_VERSION] * 8)
{
MESSAGE_UP_TO_TERMINATOR := MESSAGE_CODE . MESSAGE_STRING . "0"
}
Else
{
MESSAGE_UP_TO_TERMINATOR := MESSAGE_CODE . MESSAGE_STRING
}
; We now see how many more zeroes we have to add till we get a multiple of 8 in the total bit length and add these after the teminator.
MESSAGE_PAD_MULTIPLE_8 := MESSAGE_UP_TO_TERMINATOR ; note that MESSAGE_PAD_MULTIPLE_8 is only completed (in its namesake) below.
If !(Mod(StrLen(MESSAGE_UP_TO_TERMINATOR), 8) = 0) ; If the number of bits in the string we have up till now is not a multiple of 8...
{
Loop % 8 - Mod(StrLen(MESSAGE_UP_TO_TERMINATOR), 8) ; We add zeros till the number of bits is a multiple of 8.
{
MESSAGE_PAD_MULTIPLE_8 := MESSAGE_PAD_MULTIPLE_8 . "0"
}
}
NUMBER_OF_RIGHT_BYTE_PADS_TO_ADD := ((TOTAL_CODEWORDS[CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_VERSION] * 8) - StrLen(MESSAGE_PAD_MULTIPLE_8)) / 8
FINAL_MESSAGE_RAW_DATA_BITS := MESSAGE_PAD_MULTIPLE_8 ; Again, note that FINAL_MESSAGE_RAW_DATA_BITS is only completed (in its namesake) below. We are including the right pad bytes to make the the message equal to the full capacity of the version.
; Now that we have the message, terminator and zero padded bits, we add the byte padds, which are alternating sequences of the bytes 236 and 17 up to the filled capacity of cordewords for the version and ECL.
Loop % NUMBER_OF_RIGHT_BYTE_PADS_TO_ADD
{
if (Mod(A_Index, 2) = 1)
FINAL_MESSAGE_RAW_DATA_BITS := FINAL_MESSAGE_RAW_DATA_BITS . "11101100" ; 236
else
FINAL_MESSAGE_RAW_DATA_BITS := FINAL_MESSAGE_RAW_DATA_BITS . "00010001" ; 17
}
GROUPS_AND_BLOCKS_INFO := ""
GROUPS_AND_BLOCKS_INFO := BLOCKS_AND_GROUPS[CHOOSEN_ERROR_CORRECTION_LEVEL, CHOOSEN_VERSION]
StringSplit, GROUPS_AND_BLOCKS_INFO_, GROUPS_AND_BLOCKS_INFO , |
MESSAGE_BITS_TO_SPLIT := FINAL_MESSAGE_RAW_DATA_BITS
; For each block, we will generate an ECW set.
NUMBER_OF_BITS_PER_BLOCK := ""
NUMBER_OF_BITS_PER_BLOCK := GROUPS_AND_BLOCKS_INFO_3 * 8
Loop % GROUPS_AND_BLOCKS_INFO_1 ; Blocks in Group 1
{
BLOCK_%A_Index%_OF_GROUP_1 := SubStr(MESSAGE_BITS_TO_SPLIT, 1, NUMBER_OF_BITS_PER_BLOCK)
StringTrimLeft, MESSAGE_BITS_TO_SPLIT, MESSAGE_BITS_TO_SPLIT, %NUMBER_OF_BITS_PER_BLOCK%
GENERATE_ERROR_CORRECTION_CODEWORDS(BLOCK_%A_Index%_OF_GROUP_1, CHOOSEN_ERROR_CORRECTION_LEVEL, 1, A_Index, CHOOSEN_VERSION)
}
NUMBER_OF_BITS_PER_BLOCK := ""
NUMBER_OF_BITS_PER_BLOCK := GROUPS_AND_BLOCKS_INFO_4 * 8
Loop % GROUPS_AND_BLOCKS_INFO_2 ; Blocks in Group 2
{
BLOCK_%A_Index%_OF_GROUP_2 := SubStr(MESSAGE_BITS_TO_SPLIT, 1, NUMBER_OF_BITS_PER_BLOCK)
StringTrimLeft, MESSAGE_BITS_TO_SPLIT, MESSAGE_BITS_TO_SPLIT, %NUMBER_OF_BITS_PER_BLOCK%
GENERATE_ERROR_CORRECTION_CODEWORDS(BLOCK_%A_Index%_OF_GROUP_2, CHOOSEN_ERROR_CORRECTION_LEVEL, 2, A_Index, CHOOSEN_VERSION)
}
; So basically, we now have each of the bytes of the final message allocated in their corresponding groups and blocks. To access the first byte of the first group of the first block, we would than use the first byte of BLOCK_1_OF_GROUP_1. To access the first byte of the first ECW string (the first one related to the first block of the first group of CW) we would than use: SubStr("00000000" . Bin(ERROR_CORRECTION_CODEWORDS_1_1[1]), -7, 8). Time to proceed the interleaving.
; First, we interleave the CW Bytes.
HIGHEST_NUMBER_OF_BLOCKS_PER_GROUP := ""
% ((GROUPS_AND_BLOCKS_INFO_3 > GROUPS_AND_BLOCKS_INFO_4) ? (HIGHEST_NUMBER_OF_BLOCKS_PER_GROUP := GROUPS_AND_BLOCKS_INFO_3) : (HIGHEST_NUMBER_OF_BLOCKS_PER_GROUP := GROUPS_AND_BLOCKS_INFO_4))
Loop % HIGHEST_NUMBER_OF_BLOCKS_PER_GROUP
{
CURRENT_COLUMN := A_Index
Loop % (GROUPS_AND_BLOCKS_INFO_1 + GROUPS_AND_BLOCKS_INFO_2)
{
If (A_Index <= GROUPS_AND_BLOCKS_INFO_1)
{
INTERLEAVED_MESSAGE_BITS := INTERLEAVED_MESSAGE_BITS . SubStr(BLOCK_%A_Index%_OF_GROUP_1, CURRENT_COLUMN * 8 - 7, 8)
}
If (A_Index > GROUPS_AND_BLOCKS_INFO_1)
{
CURRENT_BLOCK_NUMBER := A_Index - GROUPS_AND_BLOCKS_INFO_1
INTERLEAVED_MESSAGE_BITS := INTERLEAVED_MESSAGE_BITS . SubStr(BLOCK_%CURRENT_BLOCK_NUMBER%_OF_GROUP_2, CURRENT_COLUMN * 8 - 7, 8)
}
}
}
CURRENT_COLUMN := ""
; And than, we interleave the ECW bytes.
Loop % NUMBER_OF_ECW
{
CURRENT_COLUMN := A_Index
Loop % (GROUPS_AND_BLOCKS_INFO_1 + GROUPS_AND_BLOCKS_INFO_2)
{
If (A_Index <= GROUPS_AND_BLOCKS_INFO_1)
{
INTERLEAVED_ECW_BITS := INTERLEAVED_ECW_BITS . SubStr("00000000" . Bin(ERROR_CORRECTION_CODEWORDS_1_%A_Index%[CURRENT_COLUMN]), -7, 8)
}
If (A_Index > GROUPS_AND_BLOCKS_INFO_1)
{
CURRENT_BLOCK_NUMBER := A_Index - GROUPS_AND_BLOCKS_INFO_1
INTERLEAVED_ECW_BITS := INTERLEAVED_ECW_BITS . SubStr("00000000" . Bin(ERROR_CORRECTION_CODEWORDS_2_%CURRENT_BLOCK_NUMBER%[CURRENT_COLUMN]), -7, 8)
}
}
}
CURRENT_COLUMN := ""
FINAL_MESSAGE := INTERLEAVED_MESSAGE_BITS . INTERLEAVED_ECW_BITS ; This string contains the full unencoded structured message, without any error correction code.
MATRIX_TO_PRINT := GENERATE_MATRIX(FINAL_MESSAGE, CHOOSEN_VERSION, CHOOSEN_ERROR_CORRECTION_LEVEL)
; We are finally done. All that is left before printing is to insert the Version and Format information.The first string goes of the Format information goes below.
MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, 0, 1), MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS - 1] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -1, 1), MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS - 2] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -2, 1), MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS - 3] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -3, 1), MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS - 4] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -4, 1), MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS - 5] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -5, 1), MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS - 6] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -6, 1), MATRIX_TO_PRINT[9, MATRIX_DIMENSIONS - 7] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -7, 1), MATRIX_TO_PRINT[MATRIX_DIMENSIONS - 6, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -8, 1), MATRIX_TO_PRINT[MATRIX_DIMENSIONS - 5, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -9, 1), MATRIX_TO_PRINT[MATRIX_DIMENSIONS - 4, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -10, 1), MATRIX_TO_PRINT[MATRIX_DIMENSIONS - 3, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -11, 1), MATRIX_TO_PRINT[MATRIX_DIMENSIONS - 2, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -12, 1), MATRIX_TO_PRINT[MATRIX_DIMENSIONS - 1, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -13, 1), MATRIX_TO_PRINT[MATRIX_DIMENSIONS, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -14, 1)
; And now the second string with the Format Info.
MATRIX_TO_PRINT[1, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, 0, 1), MATRIX_TO_PRINT[2, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -1, 1), MATRIX_TO_PRINT[3, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -2, 1), MATRIX_TO_PRINT[4, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -3, 1), MATRIX_TO_PRINT[5, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -4, 1), MATRIX_TO_PRINT[6, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -5, 1), MATRIX_TO_PRINT[8, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -6, 1), MATRIX_TO_PRINT[9, 9] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -7, 1), MATRIX_TO_PRINT[9, 8] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -8, 1), MATRIX_TO_PRINT[9, 6] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -9, 1), MATRIX_TO_PRINT[9, 5] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -10, 1), MATRIX_TO_PRINT[9, 4] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -11, 1), MATRIX_TO_PRINT[9, 3] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -12, 1), MATRIX_TO_PRINT[9, 2] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -13, 1), MATRIX_TO_PRINT[9, 1] := SubStr(CHOOSEN_MASK_CODE_FOR_V2, -14, 1)
; Version information strings exist only on QR matrixes versions 7 and above.
If (CHOOSEN_VERSION >= 7)
{
VERSION_INFORMATION_STRING := ""
% ((CHOOSEN_VERSION = 7) ? (VERSION_INFORMATION_STRING := "000111110010010100") : ("")), ((CHOOSEN_VERSION = 8) ? (VERSION_INFORMATION_STRING := "001000010110111100") : ("")), ((CHOOSEN_VERSION = 9) ? (VERSION_INFORMATION_STRING := "001001101010011001") : ("")), ((CHOOSEN_VERSION = 10) ? (VERSION_INFORMATION_STRING := "001010010011010011") : ("")), ((CHOOSEN_VERSION = 11) ? (VERSION_INFORMATION_STRING := "001011101111110110") : ("")), ((CHOOSEN_VERSION = 12) ? (VERSION_INFORMATION_STRING := "001100011101100010") : ("")), ((CHOOSEN_VERSION = 13) ? (VERSION_INFORMATION_STRING := "001101100001000111") : ("")), ((CHOOSEN_VERSION = 14) ? (VERSION_INFORMATION_STRING := "001110011000001101") : ("")), ((CHOOSEN_VERSION = 15) ? (VERSION_INFORMATION_STRING := "001111100100101000") : ("")), ((CHOOSEN_VERSION = 16) ? (VERSION_INFORMATION_STRING := "010000101101111000") : ("")), ((CHOOSEN_VERSION = 17) ? (VERSION_INFORMATION_STRING := "010001010001011101") : ("")), ((CHOOSEN_VERSION = 18) ? (VERSION_INFORMATION_STRING := "010010101000010111") : ("")), ((CHOOSEN_VERSION = 19) ? (VERSION_INFORMATION_STRING := "010011010100110010") : ("")), ((CHOOSEN_VERSION = 20) ? (VERSION_INFORMATION_STRING := "010100100110100110") : (""))
% ((CHOOSEN_VERSION = 21) ? (VERSION_INFORMATION_STRING := "010101011010000011") : ("")), ((CHOOSEN_VERSION = 22) ? (VERSION_INFORMATION_STRING := "010110100011001001") : ("")), ((CHOOSEN_VERSION = 23) ? (VERSION_INFORMATION_STRING := "010111011111101100") : ("")), ((CHOOSEN_VERSION = 24) ? (VERSION_INFORMATION_STRING := "011000111011000100") : ("")), ((CHOOSEN_VERSION = 25) ? (VERSION_INFORMATION_STRING := "011001000111100001") : ("")), ((CHOOSEN_VERSION = 26) ? (VERSION_INFORMATION_STRING := "011010111110101011") : ("")), ((CHOOSEN_VERSION = 27) ? (VERSION_INFORMATION_STRING := "011011000010001110") : ("")), ((CHOOSEN_VERSION = 28) ? (VERSION_INFORMATION_STRING := "011100110000011010") : ("")), ((CHOOSEN_VERSION = 29) ? (VERSION_INFORMATION_STRING := "011101001100111111") : ("")), ((CHOOSEN_VERSION = 30) ? (VERSION_INFORMATION_STRING := "011110110101110101") : ("")), ((CHOOSEN_VERSION = 31) ? (VERSION_INFORMATION_STRING := "011111001001010000") : ("")), ((CHOOSEN_VERSION = 32) ? (VERSION_INFORMATION_STRING := "100000100111010101") : ("")), ((CHOOSEN_VERSION = 33) ? (VERSION_INFORMATION_STRING := "100001011011110000") : ("")), ((CHOOSEN_VERSION = 34) ? (VERSION_INFORMATION_STRING := "100010100010111010") : ("")), ((CHOOSEN_VERSION = 35) ? (VERSION_INFORMATION_STRING := "100011011110011111") : ("")), ((CHOOSEN_VERSION = 36) ? (VERSION_INFORMATION_STRING := "100100101100001011") : ("")), ((CHOOSEN_VERSION = 37) ? (VERSION_INFORMATION_STRING := "100101010000101110") : ("")), ((CHOOSEN_VERSION = 38) ? (VERSION_INFORMATION_STRING := "100110101001100100") : ("")), ((CHOOSEN_VERSION = 39) ? (VERSION_INFORMATION_STRING := "100111010101000001") : ("")), ((CHOOSEN_VERSION = 40) ? (VERSION_INFORMATION_STRING := "101000110001101001") : (""))
Loop 6
{
CURRENT_COLUMN := A_Index
Loop 3
{
CURRENT_ROW := A_Index
MATRIX_TO_PRINT[MATRIX_DIMENSIONS - (11 - A_Index), CURRENT_COLUMN] := SubStr(VERSION_INFORMATION_STRING, 1 - (A_Index + (CURRENT_COLUMN * 3 - 2) - 1), 1)
MATRIX_TO_PRINT[CURRENT_COLUMN, MATRIX_DIMENSIONS - (11 - A_Index)] := SubStr(VERSION_INFORMATION_STRING, 1 - (A_Index + (CURRENT_COLUMN * 3 - 2) - 1), 1)
}
}
}
; Time to get rid of the global trash.
Loop % GROUPS_AND_BLOCKS_INFO_1
{
BLOCK_%A_Index%_OF_GROUP_1 := ""
ERROR_CORRECTION_CODEWORDS_1_%A_Index% := ""
}
Loop % GROUPS_AND_BLOCKS_INFO_2
{
BLOCK_%A_Index%_OF_GROUP_2 := ""
ERROR_CORRECTION_CODEWORDS_2_%A_Index% := ""
}
Loop % ALIGNMENT_INDIVIDUAL_COORDINATES_0
{
ALIGNMENT_INDIVIDUAL_COORDINATES_%A_Index% := ""
}
CHOOSEN_MASK_CODE_FOR_V2 := "", ERROR_CORRECTION_CODEWORDS := "", CURRENT_COLUMN := "", CURRENT_GROUP := "", CURRENT_REDIMENSION_ROW := "", ERROR_CORRECTION_CODEWORDS_BITS := "", FINAL_MESSAGE := "", FINAL_MESSAGE_RAW_DATA_BITS := "", G := "", LIST_OF_PENALTY_VALUES := "", Loop_Times := "", MATRIX_MASK_ONE := "", MATRIX_MASK_TWO := "", MATRIX_MASK_THREE := "", MATRIX_MASK_FOUR := "", MATRIX_MASK_FIVE := "", MATRIX_MASK_SIX := "", MATRIX_MASK_SEVEN := "", MATRIX_MASK_EIGHT := "", MATRIX_UNMASKED := "", MESSAGE_PAD_MULTIPLE_8 := "", MESSAGE_STRING := "", MESSAGE_TO_ENCODE := "", MESSAGE_UP_TO_TERMINATOR := "", NUMBER_OF_BITS_TO_USE := "", NUMBER_OF_RIGHT_BYTE_PADS_TO_ADD := "", Numeric_Mode := "", Options := "", pBitmap := "", pBrush := "", PENALTY_VALUES_IN_ORDER0 := "", PENALTY_VALUES_IN_ORDER1 := "", PENALTY_VALUES_IN_ORDER2 := "", PENALTY_VALUES_IN_ORDER3 := "", PENALTY_VALUES_IN_ORDER4 := "", PENALTY_VALUES_IN_ORDER5 := "", PENALTY_VALUES_IN_ORDER6 := "", PENALTY_VALUES_IN_ORDER7 := "", PENALTY_VALUES_IN_ORDER8 := "", pToken := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_1 := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_2 := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_3 := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_4 := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_5 := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_6 := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_7 := "", TOTAL_PENALTY_FOR_MASKED_MATRIX_8 := "", MESSAGE_CODE := "", NUMBER_OF_ECW := "", CHOOSEN_ERROR_CORRECTION_LEVEL := "", CHOOSEN_CODE_MODE := "", CURRENT_ROW := "", CURRENT_ROW_OF_FUNCTION_PATTERN := "", CURRENT_WRITING_DIRECTION := "", FILE_PATH_AND_NAME := "", FUNCTION_ALIGN_PATTERN_CURRENT_ROW := "", FUNCTION_ALIGNMENT_PATTERN := "", FUNCTION_FINDER_PATTERN := "", GROUPS_AND_BLOCKS_INFO := "", GROUPS_AND_BLOCKS_INFO_0 := "", GROUPS_AND_BLOCKS_INFO_1 := "", GROUPS_AND_BLOCKS_INFO_2 := "", GROUPS_AND_BLOCKS_INFO_3 := "", GROUPS_AND_BLOCKS_INFO_4 := "", CURRENT_BLOCK_NUMBER := "", COMPOSITE_VERSION := "", Column_Count := "", CHOOSEN_VERSION := "", Char_Count := "", INTERLEAVED_ECW_BITS := "", INTERLEAVED_MESSAGE_BITS := "", LIST_OF_PENALTY_VALUES := "", MATRIX_DIMENSIONS := "", LOWER_MULTIPLE_OF_5 := "", NEAREST_MULTIPLE_OF_TEN := "", NOT_WRITE := "", NUMBER_OF_BITS_PER_BLOCK := "", NUMBER_OF_DARK_MODULES := "", NUMBER_OF_LIGHT_MODULES := "", PENALTY_SUM := "", PERCENT_OF_MODULES := "", PREVIOUS_BIT := "", RESULT_ONE := "", RESULT_TWO := "", Row_Count := "", SEQUENCE_TO_CHECK := "", START_BIT := "", TOTAL_CODEWORDS := "", TOTAL_MODULES := "", VERSION_INFORMATION_STRING := "", UPPER_MULTIPLE_OF_5 := "", INDIVIDUAL_ALIGNMENT_COORDS_0 := "", INDIVIDUAL_ALIGNMENT_COORDS_1 := "", INDIVIDUAL_ALIGNMENT_COORDS_2 := "", HIGHEST_NUMBER_OF_BLOCKS_PER_GROUP := "", COUNT_CONTINUOUS := "", CURRENT_ENTRY := "", ALIGNMENT_LOCATIONS := "", ALIGNMENT_INDIVIDUAL_COORDINATES_0 := "", COUNTER := "", FILE_NAME_TO_USE := "", BYTE_MODE := "", ALPHANUMERIC_MODE := "", Bits_Of_Last_Group := ""
Return MATRIX_TO_PRINT
}
Return
; To encode alphanumeric characters, the table below is required.
GENERATE_ALPHANUMERIC_TABLE()
{
Global
ALPHA_TABLE := object()
ALPHA_TABLE[0] := 0, ALPHA_TABLE[1] := 1, ALPHA_TABLE[2] := 2, ALPHA_TABLE[3] := 3, ALPHA_TABLE[4] := 4, ALPHA_TABLE[5] := 5, ALPHA_TABLE[6] := 6, ALPHA_TABLE[7] := 7, ALPHA_TABLE[8] := 8, ALPHA_TABLE[9] := 9, ALPHA_TABLE["A"] := 10, ALPHA_TABLE["B"] := 11, ALPHA_TABLE["C"] := 12, ALPHA_TABLE["D"] := 13, ALPHA_TABLE["E"] := 14, ALPHA_TABLE["F"] := 15, ALPHA_TABLE["G"] := 16, ALPHA_TABLE["H"] := 17, ALPHA_TABLE["I"] := 18, ALPHA_TABLE["J"] := 19, ALPHA_TABLE["K"] := 20, ALPHA_TABLE["L"] := 21, ALPHA_TABLE["M"] := 22, ALPHA_TABLE["N"] := 23, ALPHA_TABLE["O"] := 24, ALPHA_TABLE["P"] := 25, ALPHA_TABLE["Q"] := 26, ALPHA_TABLE["R"] := 27, ALPHA_TABLE["S"] := 28, ALPHA_TABLE["T"] := 29, ALPHA_TABLE["U"] := 30, ALPHA_TABLE["V"] := 31, ALPHA_TABLE["W"] := 32, ALPHA_TABLE["X"] := 33, ALPHA_TABLE["Y"] := 34, ALPHA_TABLE["Z"] := 35, ALPHA_TABLE[A_Space] := 36, ALPHA_TABLE["`$"] := 37, ALPHA_TABLE["`%"] := 38, ALPHA_TABLE["`*"] := 39, ALPHA_TABLE["`+"] := 40, ALPHA_TABLE["`-"] := 41, ALPHA_TABLE["`."] := 42, ALPHA_TABLE["`/"] := 43, ALPHA_TABLE["`:"] := 44
}
Return
;The function below generates a 3D object (CAPACITY_CUBE) to hold the capacity of the QR Matrix according to Version, ECL and Code Mode.
GENERATE_VERSION_CAPACITY_CUBE()
{
global
CAPACITY_CUBE := object()
CAPACITY_STRING := "41 25 17 10 34 20 14 8 27 16 11 7 17 10 7 4 77 47 32 20 63 38 26 16 48 29 20 12 34 20 14 8 127 77 53 32 101 61 42 26 77 47 32 20 58 35 24 15 187 114 78 48 149 90 62 38 111 67 46 28 82 50 34 21 255 154 106 65 202 122 84 52 144 87 60 37 106 64 44 27 322 195 134 82 255 154 106 65 178 108 74 45 139 84 58 36 370 224 154 95 293 178 122 75 207 125 86 53 154 93 64 39 461 279 192 118 365 221 152 93 259 157 108 66 202 122 84 52 552 335 230 141 432 262 180 111 312 189 130 80 235 143 98 60 652 395 271 167 513 311 213 131 364 221 151 93 288 174 119 74 772 468 321 198 604 366 251 155 427 259 177 109 331 200 137 85 883 535 367 226 691 419 287 177 489 296 203 125 374 227 155 96 1022 619 425 262 796 483 331 204 580 352 241 149 427 259 177 109 1101 667 458 282 871 528 362 223 621 376 258 159 468 283 194 120 1250 758 520 320 991 600 412 254 703 426 292 180 530 321 220 136 1408 854 586 361 1082 656 450 277 775 470 322 198 602 365 250 154 1548 938 644 397 1212 734 504 310 876 531 364 224 674 408 280 173 1725 1046 718 442 1346 816 560 345 948 574 394 243 746 452 310 191 1903 1153 792 488 1500 909 624 384 1063 644 442 272 813 493 338 208 2061 1249 858 528 1600 970 666 410 1159 702 482 297 919 557 382 235 2232 1352 929 572 1708 1035 711 438 1224 742 509 314 969 587 403 248 2409 1460 1003 618 1872 1134 779 480 1358 823 565 348 1056 640 439 270 2620 1588 1091 672 2059 1248 857 528 1468 890 611 376 1108 672 461 284 2812 1704 1171 721 2188 1326 911 561 1588 963 661 407 1228 744 511 315 3057 1853 1273 784 2395 1451 997 614 1718 1041 715 440 1286 779 535 330 3283 1990 1367 842 2544 1542 1059 652 1804 1094 751 462 1425 864 593 365 3517 2132 1465 902 2701 1637 1125 692 1933 1172 805 496 1501 910 625 385 3669 2223 1528 940 2857 1732 1190 732 2085 1263 868 534 1581 958 658 405 3909 2369 1628 1002 3035 1839 1264 778 2181 1322 908 559 1677 1016 698 430 4158 2520 1732 1066 3289 1994 1370 843 2358 1429 982 604 1782 1080 742 457 4417 2677 1840 1132 3486 2113 1452 894 2473 1499 1030 634 1897 1150 790 486 4686 2840 1952 1201 3693 2238 1538 947 2670 1618 1112 684 2022 1226 842 518 4965 3009 2068 1273 3909 2369 1628 1002 2805 1700 1168 719 2157 1307 898 553 5253 3183 2188 1347 4134 2506 1722 1060 2949 1787 1228 756 2301 1394 958 590 5529 3351 2303 1417 4343 2632 1809 1113 3081 1867 1283 790 2361 1431 983 605 5836 3537 2431 1496 4588 2780 1911 1176 3244 1966 1351 832 2524 1530 1051 647 6153 3729 2563 1577 4775 2894 1989 1224 3417 2071 1423 876 2625 1591 1093 673 6479 3927 2699 1661 5039 3054 2099 1292 3599 2181 1499 923 2735 1658 1139 701 6743 4087 2809 1729 5313 3220 2213 1362 3791 2298 1579 972 2927 1774 1219 750 7089 4296 2953 1817 5596 3391 2331 1435 3993 2420 1663 1024 3057 1852 1273 784"
StringSplit, CAPACITY_STRING_, CAPACITY_STRING, %A_Tab%
Loop 40 ; There are 40 different QR Code versions (excluding Micro Qr Codes).
{
CURRENT_VERSION := A_Index
Loop 4 ; There are 4 different Error Correction Levels (L, M, Q, and H, from lowest to highest. Low ECL = higher capacity, but high ECL = more reliable reading if the matrix code is damaged).
{
CURRENT_ECL := A_Index
Loop 4 ; There are 4 different types of encoded data in QR Code. Numeric, AlphaNumeric, Byte and Kanji.
{
CURRENT_TYPE := A_Index
CURRENT_ADDRESS := ((CURRENT_VERSION - 1) * 16) + ((CURRENT_ECL - 1) * 4) + CURRENT_TYPE
CAPACITY_CUBE[CURRENT_VERSION, CURRENT_ECL, CURRENT_TYPE] := CAPACITY_STRING_%CURRENT_ADDRESS%
CAPACITY_STRING_%CURRENT_ADDRESS% := ""
}
}
}
CURRENT_VERSION := "", CURRENT_ECL := "", CURRENT_TYPE := "", CURRENT_ADDRESS := "", CAPACITY_STRING_0 := "", CAPACITY_STRING := ""
}
Return
CONVERT_TO_NUMERIC_ENCODING(MESSAGE_TO_ENCODE)
{
Global
MESSAGE_STRING := ""
Bits_Of_Last_Group := 10
If (Mod(StrLen(MESSAGE_TO_ENCODE), 3) = 2) ; If the last group is 2 digits long, it will be encoded as a 7 bits long binary number.
{
Bits_Of_Last_Group := 7
}
If (Mod(StrLen(MESSAGE_TO_ENCODE), 3) = 1) ; If the last group is 1 digit long, it will be encoded as a 4 bits long binary number.
{
Bits_Of_Last_Group := 4
}
Loop_Times := Ceil(StrLen(MESSAGE_TO_ENCODE) / 3) ; Numeric messages are encoded 3 digits a time.
Message_Left := MESSAGE_TO_ENCODE ; This will be cut 3 digit a time in the loop bellow (to form the binary string).
NUMBER_OF_BITS_TO_USE := 10 ; Initially, we will make sure every group has a total of 10 bits (appending as many zeros as necessary).
Loop % Loop_Times ; This conditional executes once for every 3 digits in the message (rounded up).
{
If (A_Index = Loop_Times) ; If this is the last group, check the ammount of bits to pad according to variable Bits_Of_Last_Group.
{
NUMBER_OF_BITS_TO_USE := Bits_Of_Last_Group
}
Current_Group := SubStr(Message_Left, 1, 3)
MESSAGE_STRING := MESSAGE_STRING . SubStr("0000000000" . Bin(Current_Group), 1 - NUMBER_OF_BITS_TO_USE, NUMBER_OF_BITS_TO_USE) ; Explaining this: We are padding as many zeros as the groups max size to the binary string in the line above, and than we are getting the last NUMBER_OF_BITS_TO_USE digits of the concatenated result. This ensures that all and only the required zeros are padded to the string, whichever size .
Message_Left := SubStr(Message_Left, 4)
}
Return MESSAGE_STRING
}
Return
CONVERT_TO_ALPHANUMERIC_ENCODING(MESSAGE_TO_ENCODE) ; Numeric messages are encoded 3 bits at a time in a 10 digit binary number (except for the last group, which may be 10, 7 or 4, depending on its length)
{
Global
MESSAGE_STRING := ""
Bits_Of_Last_Group := 11
If (Mod(StrLen(MESSAGE_TO_ENCODE), 2) = 1) ; If the string length is an odd number, the last character shall be encoded using 6 bits.
{
Bits_Of_Last_Group := 6
}
Loop_Times := Ceil(StrLen(MESSAGE_TO_ENCODE) / 2) ; Numeric messages are encoded 3 digits a time.
Message_Left := MESSAGE_TO_ENCODE ; This will be cut 3 digit a time in the loop bellow (to form the binary string).
NUMBER_OF_BITS_TO_USE := 11 ; Initially, we will make sure every group has a total of 11 bits (appending as many zeros as necessary).
Loop % Loop_Times ; This conditional executes once for every 3 digits in the message (rounded up).
{
If (A_Index = Loop_Times) ; If this is the last group, check the ammount of bits to pad according to variable Bits_Of_Last_Group.
{
NUMBER_OF_BITS_TO_USE := Bits_Of_Last_Group
}
Current_Group := SubStr(Message_Left, 1, 2)
FIRST_CHAR := SubStr(Current_Group, 1, 1)
SECOND_CHAR := SubStr(Current_Group, 2, 1)
if ((A_Index != Loop_Times) OR ((Mod(StrLen(MESSAGE_TO_ENCODE), 2) = 0)))
{
MESSAGE_STRING := MESSAGE_STRING . SubStr("00000000000" . Bin((ALPHA_TABLE[FIRST_CHAR] * 45) + ALPHA_TABLE[SECOND_CHAR]), 1 - NUMBER_OF_BITS_TO_USE, NUMBER_OF_BITS_TO_USE) ; Explaining this: We are padding as many zeros as the groups max size to the binary string in the line above, and than we are getting the last NUMBER_OF_BITS_TO_USE digits of the concatenated result. This ensures that all and only the required zeros are padded to the string, whichever size .
Message_Left := SubStr(Message_Left, 3)
}
If ((A_Index = Loop_Times) AND (Mod(StrLen(MESSAGE_TO_ENCODE), 2) = 1))
{
MESSAGE_STRING := MESSAGE_STRING . SubStr("00000000000" . Bin(ALPHA_TABLE[FIRST_CHAR]), 1 - NUMBER_OF_BITS_TO_USE, NUMBER_OF_BITS_TO_USE) ; Explaining this: We are padding as many zeros as the groups max size to the binary string in the line above, and than we are getting the last NUMBER_OF_BITS_TO_USE digits of the concatenated result. This ensures that all and only the required zeros are padded to the string, whichever size .
Message_Left := SubStr(Message_Left, 3)
}
}
Return MESSAGE_STRING
}
Return
CONVERT_TO_BYTE_ENCODING(MESSAGE_TO_ENCODE)
{
Global
MESSAGE_STRING := ""
Loop_Times := StrLen(MESSAGE_TO_ENCODE) ; Byte messages are encoded 1 char at a time.
Message_Left := MESSAGE_TO_ENCODE
NUMBER_OF_BITS_TO_USE := 8 ; Initially, we will make sure every group has a total of 8 bits (appending as many zeros as necessary).
Loop % Loop_Times
{
Current_Group := SubStr(Message_Left, 1, 1)
MESSAGE_STRING := MESSAGE_STRING . SubStr("00000000" . Bin(Asc(Current_Group)), 1 - NUMBER_OF_BITS_TO_USE, NUMBER_OF_BITS_TO_USE) ; Explaining this: We are padding as many zeros as the groups max size to the binary string in the line above, and than we are getting the last NUMBER_OF_BITS_TO_USE digits of the concatenated result. This ensures that all and only the required zeros are padded to the string, whichever size .
Message_Left := SubStr(Message_Left, 2)
}
Return MESSAGE_STRING
}
Return
GET_GENERATOR_POLYNOMIAL(CHOOSEN_VERSION, CHOOSEN_ERROR_CORRECTION_LEVEL) ; Here we calculate the generator polynomial required.
{
Global
; The Generator polynomial for the Error Correction Words (ECW) is a result of the expression (X - a**0) * (X - a**1) * (X - a**2) ... (X - a**[n-1]) where n is equal do the number of codewords that must be generated.
; This means that if you were to need a generator for 2 ECW, you would simply get a simplified galois field abiding form of (X - a**0) * (X - a**1), which is actually (a**0 * x**2 + a**25 * x**1 + a**1 * x**0).
; A generator for 3 Error Correction Words is achieved simply by multiplying the generator for 2 ECW with (X-a**2). And so on for the next generators. More info on http://www.thonky.com/qr-code-tutorial/error-correction-coding/#step-7-understanding-the-generator-polynomial
; Although it is thereby possible to generate a calculator for any generator polynomials based on required ECW, coding such a routine seems to be a waste of processing power since you only got 13 possible generator polynomials anyways. The ISO 18004 also gives the possible generators in an annex table.
COMPOSITE_VERSION := CHOOSEN_VERSION . "-" . CHOOSEN_ERROR_CORRECTION_LEVEL ; This has been assigned on an earlier call to GET_NUMBER_OF_GROUPS_AND_BLOCKS.
if (COMPOSITE_VERSION = "1-1") ; 1-L. 7 ECW.
{
NUMBER_OF_ECW := 7
Loop, 7
GENERATOR_X%A_Index% := 8 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 87, GENERATOR_A3 := 229, GENERATOR_A4 := 146, GENERATOR_A5 := 149, GENERATOR_A6 := 238, GENERATOR_A7 := 102, GENERATOR_A8 := 21
Return
}
If COMPOSITE_VERSION in 1-2,2-1 ; 1-M , 2-L. 10 ECW. ANY SPACES AND TABS AROUND THE COMMAS ARE SIGNIFICANT FOR IF VAR IN MATCHLIST !!
{
NUMBER_OF_ECW := 10
Loop, 10
GENERATOR_X%A_Index% := 11 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 251, GENERATOR_A3 := 67, GENERATOR_A4 := 46, GENERATOR_A5 := 61, GENERATOR_A6 := 118, GENERATOR_A7 := 70, GENERATOR_A8 := 64, GENERATOR_A9 := 94, GENERATOR_A10 := 32, GENERATOR_A11 := 45
Return
}
If COMPOSITE_VERSION in 1-3 ; 1-Q. 13 ECW
{
NUMBER_OF_ECW := 13
Loop, 13
GENERATOR_X%A_Index% := 14 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 74, GENERATOR_A3 := 152, GENERATOR_A4 := 176, GENERATOR_A5 := 100, GENERATOR_A6 := 86, GENERATOR_A7 := 100, GENERATOR_A8 := 106, GENERATOR_A9 := 104, GENERATOR_A10 := 130, GENERATOR_A11 := 218, GENERATOR_A12 := 206, GENERATOR_A13 := 140, GENERATOR_A14 := 78
Return
}
If COMPOSITE_VERSION in 3-1 ; 3-L. 15 ECW
{
NUMBER_OF_ECW := 15
Loop, 15
GENERATOR_X%A_Index% := 16 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 8, GENERATOR_A3 := 183, GENERATOR_A4 := 61, GENERATOR_A5 := 91, GENERATOR_A6 := 202, GENERATOR_A7 := 37, GENERATOR_A8 := 51, GENERATOR_A9 := 58, GENERATOR_A10 := 58, GENERATOR_A11 := 237, GENERATOR_A12 := 140, GENERATOR_A13 := 124, GENERATOR_A14 := 5, GENERATOR_A15 := 99, GENERATOR_A16 := 105
Return
}
If COMPOSITE_VERSION in 2-2,4-4,6-2 ; 2-M, 4-H, 6-M. 16 ECW
{
NUMBER_OF_ECW := 16
Loop, 16
GENERATOR_X%A_Index% := 17 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 120, GENERATOR_A3 := 104, GENERATOR_A4 := 107, GENERATOR_A5 := 109, GENERATOR_A6 := 102, GENERATOR_A7 := 161, GENERATOR_A8 := 76, GENERATOR_A9 := 3, GENERATOR_A10 := 91, GENERATOR_A11 := 191, GENERATOR_A12 := 147, GENERATOR_A13 := 169, GENERATOR_A14 := 182, GENERATOR_A15 := 194, GENERATOR_A16 := 225, GENERATOR_A17 := 120
Return
}
If COMPOSITE_VERSION in 1-4 ; 1-H. 17 ECW
{
NUMBER_OF_ECW := 17
Loop, 17
GENERATOR_X%A_Index% := 18 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 43, GENERATOR_A3 := 139, GENERATOR_A4 := 206, GENERATOR_A5 := 78, GENERATOR_A6 := 43, GENERATOR_A7 := 239, GENERATOR_A8 := 123, GENERATOR_A9 := 206, GENERATOR_A10 := 214, GENERATOR_A11 := 147, GENERATOR_A12 := 24, GENERATOR_A13 := 99, GENERATOR_A14 := 150, GENERATOR_A15 := 39, GENERATOR_A16 := 243, GENERATOR_A17 := 163, GENERATOR_A18 := 136
Return
}
If COMPOSITE_VERSION in 3-3,4-2,5-3,6-1,7-2,7-3,10-1 ; 3-Q, 4-M, 5-Q, 6-L, 7-M, 7-Q, 10-L. 18 ECW
{
NUMBER_OF_ECW := 18
Loop, 18
GENERATOR_X%A_Index% := 19 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 215, GENERATOR_A3 := 234, GENERATOR_A4 := 158, GENERATOR_A5 := 94, GENERATOR_A6 := 184, GENERATOR_A7 := 97, GENERATOR_A8 := 118, GENERATOR_A9 := 170, GENERATOR_A10 := 79, GENERATOR_A11 := 187, GENERATOR_A12 :=152, GENERATOR_A13 := 148, GENERATOR_A14 := 252, GENERATOR_A15 := 179, GENERATOR_A16 := 5, GENERATOR_A17 := 98, GENERATOR_A18 := 96, GENERATOR_A19 := 153
Return
}
If COMPOSITE_VERSION in 4-1,7-1,9-3,11-1,14-3 ; 4-L, 7-L, 9-Q, 11-L, 14-Q. 20 ECW
{
NUMBER_OF_ECW := 20
Loop, 20
GENERATOR_X%A_Index% := 21 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 17, GENERATOR_A3 := 60, GENERATOR_A4 := 79, GENERATOR_A5 := 50, GENERATOR_A6 := 61, GENERATOR_A7 := 163, GENERATOR_A8 := 26, GENERATOR_A9 := 187, GENERATOR_A10 := 202, GENERATOR_A11 := 180, GENERATOR_A12 := 221, GENERATOR_A13 := 225, GENERATOR_A14 := 83, GENERATOR_A15 := 239, GENERATOR_A16 := 156, GENERATOR_A17 := 164, GENERATOR_A18 := 212, GENERATOR_A19 := 212, GENERATOR_A20 := 188, GENERATOR_A21 := 190
Return
}
If COMPOSITE_VERSION in 2-3,3-4,5-4,8-2,8-3,9-2,12-2,13-2,13-4,15-1 ; 2-Q, 3-H, 5-H, 8-M, 8-Q, 9-M, 12-M, 13-M, 13-H, 15-L. 22 ECW
{
NUMBER_OF_ECW := 22
Loop, 22
GENERATOR_X%A_Index% := 23 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 210, GENERATOR_A3 := 171, GENERATOR_A4 := 247, GENERATOR_A5 := 242, GENERATOR_A6 := 93, GENERATOR_A7 := 230, GENERATOR_A8 := 14, GENERATOR_A9 := 109, GENERATOR_A10 := 221, GENERATOR_A11 := 53, GENERATOR_A12 := 200, GENERATOR_A13 := 74, GENERATOR_A14 := 8, GENERATOR_A15 := 172, GENERATOR_A16 := 98, GENERATOR_A17 := 80, GENERATOR_A18 := 219, GENERATOR_A19 := 134, GENERATOR_A20 := 160, GENERATOR_A21 := 105, GENERATOR_A22 := 165, GENERATOR_A23 := 231
Return
}
If COMPOSITE_VERSION in 5-2,6-3,8-1,9-4,10-3,11-4,12-1,13-3,14-2,14-4,15-2,15-4,16-1,16-3,22-4 ; 5-M, 6-Q, 8-L, 9-H, 10-Q, 11-H, 12-L, 13-Q, 14-M, 14-H, 15-M, 15-H, 16-L, 16-Q, 22-H. 24 ECW
{
NUMBER_OF_ECW := 24
Loop, 24
GENERATOR_X%A_Index% := 25 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 229, GENERATOR_A3 := 121, GENERATOR_A4 := 135, GENERATOR_A5 := 48, GENERATOR_A6 := 211, GENERATOR_A7 := 117, GENERATOR_A8 := 251, GENERATOR_A9 := 126, GENERATOR_A10 := 159, GENERATOR_A11 := 180, GENERATOR_A12 := 169, GENERATOR_A13 := 152, GENERATOR_A14 := 192, GENERATOR_A15 := 226, GENERATOR_A16 := 228, GENERATOR_A17 := 218, GENERATOR_A18 := 111, GENERATOR_A19 := 0, GENERATOR_A20 := 117, GENERATOR_A21 := 232, GENERATOR_A22 := 87, GENERATOR_A23 := 96, GENERATOR_A24 := 227, GENERATOR_A25 := 21
Return
}
If COMPOSITE_VERSION in 3-2,4-3,5-1,7-4,8-4,10-2,12-3,13-1,18-2,19-2,19-3,19-4,20-2,21-2,25-1 ; 3-M, 4-Q, 5-L, 7-H, 8-H, 10-M, 12-Q, 13-L, 18-M, 19-M, 19-Q, 19-H, 20-M, 21-M, 25-L. 26 ECW
{
NUMBER_OF_ECW := 26
Loop, 26
GENERATOR_X%A_Index% := 27 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 173, GENERATOR_A3 := 125, GENERATOR_A4 := 158, GENERATOR_A5 := 2, GENERATOR_A6 := 103, GENERATOR_A7 := 182, GENERATOR_A8 := 118, GENERATOR_A9 := 17, GENERATOR_A10 := 145, GENERATOR_A11 := 201, GENERATOR_A12 := 111, GENERATOR_A13 := 28, GENERATOR_A14 := 165, GENERATOR_A15 := 53, GENERATOR_A16 := 161, GENERATOR_A17 := 21, GENERATOR_A18 := 245, GENERATOR_A19 := 142, GENERATOR_A20 := 13, GENERATOR_A21 := 102, GENERATOR_A22 := 48, GENERATOR_A23 := 227, GENERATOR_A24 := 153, GENERATOR_A25 := 145, GENERATOR_A26 := 218, GENERATOR_A27 := 70
Return
}
If COMPOSITE_VERSION in 2-4,6-4,10-4,11-3,12-4,16-2,17-1,17-2,17-3,17-4,18-3,18-4,19-1,20-1,20-4,21-1,21-3,22-1,22-2,23-2,24-2,25-2,26-1,26-2,26-3,27-2,28-2,29-2,30-2,31-2,32-2,33-2,34-2,35-2,36-2,37-2,38-2,39-2,40-2 ; 2-H, 6-H, 10-H, 11-Q, 12-H, 16-M, 17-L, 17-M, 17-Q, 17-H, 18-Q, 18-H, 19-L, 20-L, 20-H, 21-L, 21-Q, 22-L, 22-M, 23-M, 24-M, 25-M, 26-L, 26-M, 26-Q, 27-2, 28-M, 29-M, 30-M, 31-M, 32-M, 33-2, 34-M, 35-M, 36-M, 37-M, 38-M, 39-M, 40-M 28 ECW
{
NUMBER_OF_ECW := 28
Loop, 28
GENERATOR_X%A_Index% := 29 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 168, GENERATOR_A3 := 223, GENERATOR_A4 := 200, GENERATOR_A5 := 104, GENERATOR_A6 := 224, GENERATOR_A7 := 234, GENERATOR_A8 := 108, GENERATOR_A9 := 180, GENERATOR_A10 := 110, GENERATOR_A11 := 190, GENERATOR_A12 := 195, GENERATOR_A13 := 147, GENERATOR_A14 := 205, GENERATOR_A15 := 27, GENERATOR_A16 := 232, GENERATOR_A17 := 201, GENERATOR_A18 := 21, GENERATOR_A19 := 43, GENERATOR_A20 := 245, GENERATOR_A21 := 87, GENERATOR_A22 := 42, GENERATOR_A23 := 195, GENERATOR_A24 := 212, GENERATOR_A25 := 119, GENERATOR_A26 := 242, GENERATOR_A27 := 37, GENERATOR_A28 := 9, GENERATOR_A29 := 123
Return
}
NUMBER_OF_ECW := 30 ; If the number of ECW is not any one of the above, that means we have 30 ECW (the maximum).
Loop, 30
GENERATOR_X%A_Index% := 31 - A_Index + (StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8) - 1
GENERATOR_A1 := 0, GENERATOR_A2 := 41, GENERATOR_A3 := 173, GENERATOR_A4 := 145, GENERATOR_A5 := 152, GENERATOR_A6 := 216, GENERATOR_A7 := 31, GENERATOR_A8 := 179, GENERATOR_A9 := 182, GENERATOR_A10 := 50, GENERATOR_A11 := 48, GENERATOR_A12 := 110, GENERATOR_A13 := 86, GENERATOR_A14 := 239, GENERATOR_A15 := 96, GENERATOR_A16 := 222, GENERATOR_A17 := 125, GENERATOR_A18 := 42, GENERATOR_A19 := 173, GENERATOR_A20 := 226, GENERATOR_A21 := 193, GENERATOR_A22 := 224, GENERATOR_A23 := 130, GENERATOR_A24 := 156, GENERATOR_A25 := 37, GENERATOR_A26 := 251, GENERATOR_A27 := 216, GENERATOR_A28 := 238, GENERATOR_A29 := 40, GENERATOR_A30 := 192, GENERATOR_A31 := 180
Return
}
Return
LIST_NUMBER_OF_GROUPS_AND_BLOCKS()
{
Global
; We are going to create 4 lines (one for each ECL) with 40 entries on number of: BLOCKS IN GROUP 1|BLOCKS IN GROUP 2, CW IN BLOCKS OF GROUP 1, CW IN BLOCKS OF GROUP 2.
BLOCKS_AND_GROUPS := ""
BLOCKS_AND_GROUPS := object()
BLOCKS_AND_GROUPS[1] := ["1|0|19|0", "1|0|34|0", "1|0|55|0", "1|0|80|0", "1|0|108|0", "2|0|68|0", "2|0|78|0", "2|0|97|0", "2|0|116|0", "2|2|68|69", "4|0|81|0", "2|2|92|93", "4|0|107|0", "3|1|115|116", "5|1|87|88", "5|1|98|99", "1|5|107|108", "5|1|120|121", "3|4|113|114", "3|5|107|108", "4|4|116|117", "2|7|111|112", "4|5|121|122", "6|4|117|118", "8|4|106|107", "10|2|114|115", "8|4|122|123", "3|10|117|118", "7|7|116|117", "5|10|115|116", "13|3|115|116", "17|0|115|0", "17|1|115|116", "13|6|115|116", "12|7|121|122", "6|14|121|122", "17|4|122|123", "4|18|122|123", "20|4|117|118", "19|6|118|119"] ; The 40 values for ECL L.
BLOCKS_AND_GROUPS[2] := ["1|0|16|0", "1|0|28|0", "1|0|44|0", "2|0|32|0", "2|0|43|0", "4|0|27|0", "4|0|31|0", "2|2|38|39", "3|2|36|37", "4|1|43|44", "1|4|50|51", "6|2|36|37", "8|1|37|38", "4|5|40|41", "5|5|41|42", "7|3|45|46", "10|1|46|47", "9|4|43|44", "3|11|44|45", "3|13|41|42", "17|0|42|0", "17|0|46|0", "4|14|47|48", "6|14|45|46", "8|13|47|48", "19|4|46|47", "22|3|45|46", "3|23|45|46", "21|7|45|46", "19|10|47|48", "2|29|46|47", "10|23|46|47", "14|21|46|47", "14|23|46|47", "12|26|47|48", "6|34|47|48", "29|14|46|47", "13|32|46|47", "40|7|47|48", "18|31|47|48"] ; The 40 values for ECL M.
BLOCKS_AND_GROUPS[3] := ["1|0|13|0", "1|0|22|0", "2|0|17|0", "2|0|24|0", "2|2|15|16", "4|0|19|0", "2|4|14|15", "4|2|18|19", "4|4|16|17", "6|2|19|20", "4|4|22|23", "4|6|20|21", "8|4|20|21", "11|5|16|17", "5|7|24|25", "15|2|19|20", "1|15|22|23", "17|1|22|23", "17|4|21|22", "15|5|24|25", "17|6|22|23", "7|16|24|25", "11|14|24|25", "11|16|24|25", "7|22|24|25", "28|6|22|23", "8|26|23|24", "4|31|24|25", "1|37|23|24", "15|25|24|25", "42|1|24|25", "10|35|24|25", "29|19|24|25", "44|7|24|25", "39|14|24|25", "46|10|24|25", "49|10|24|25", "48|14|24|25", "43|22|24|25", "34|34|24|25"] ; The 40 values for ECL Q.
BLOCKS_AND_GROUPS[4] := ["1|0|9|0", "1|0|16|0", "2|0|13|0", "4|0|9|0", "2|2|11|12", "4|0|15|0", "4|1|13|14", "4|2|14|15", "4|4|12|13", "6|2|15|16", "3|8|12|13", "7|4|14|15", "12|4|11|12", "11|5|12|13", "11|7|12|13", "3|13|15|16", "2|17|14|15", "2|19|14|15", "9|16|13|14", "15|10|15|16", "19|6|16|17", "34|0|13|0", "16|14|15|16", "30|2|16|17", "22|13|15|16", "33|4|16|17", "12|28|15|16", "11|31|15|16", "19|26|15|16", "23|25|15|16", "23|28|15|16", "19|35|15|16", "11|46|15|16", "59|1|16|17", "22|41|15|16", "2|64|15|16", "24|46|15|16", "42|32|15|16", "10|67|15|16", "20|61|15|16"] ; The 40 values for ECL H.
}
Return
GENERATE_ERROR_CORRECTION_CODEWORDS(FINAL_MESSAGE_RAW_DATA_BITS, CHOOSEN_ERROR_CORRECTION_LEVEL, GROUP, BLOCK, CHOOSEN_VERSION) ; The total number of ECW depends on version and ECL.
; Generator polynomial for 28 error correction code words as an example. Numbers are exponents: x28 + a168x27 + a223x26 + a200x25 + a104x24 + a224x23 + a234x22 + a108x21 + a180x20 + a110x19 + a190x18 + a195x17 + a147x16 + a205x15 + a27x14 + a232x13 + a201x12 + a21x11 + a43x10 + a245x9 + a87x8 + a42x7 + a195x6 + a212x5 + a119x4 + a242x3 + a37x2 + a9x + a123
{
Global
GET_GENERATOR_POLYNOMIAL(CHOOSEN_VERSION, CHOOSEN_ERROR_CORRECTION_LEVEL)
MESSAGE_POLYNOMIAL := "", ERROR_CORRECTION_CODEWORDS := "" ; Free the ECW object list and the message polynomial.
MESSAGE_POLYNOMIAL := FINAL_MESSAGE_RAW_DATA_BITS
NUMBER_OF_MESSAGE_BYTES := StrLen(FINAL_MESSAGE_RAW_DATA_BITS) / 8
Loop % NUMBER_OF_MESSAGE_BYTES ; We create an index with the value of the bytes of the message.
{
BYTE_%A_Index%_OF_MESSAGE_POLYNOMIAL := Dec(SubStr(MESSAGE_POLYNOMIAL, 1, 8))
StringTrimLeft, MESSAGE_POLYNOMIAL, MESSAGE_POLYNOMIAL, 8
}
GENERATOR_FIRST := NUMBER_OF_ECW + 1 ; To be deducted on every step
; Looping routine starts here.
Loop % NUMBER_OF_MESSAGE_BYTES
{
GET_GENERATOR_POLYNOMIAL(CHOOSEN_VERSION, CHOOSEN_ERROR_CORRECTION_LEVEL)
; Step a - Multiply the Generator Polynomial by the Lead Term of the Message Polynomial
Loop % NUMBER_OF_ECW + NUMBER_OF_MESSAGE_BYTES ; below, we transform the bytes of the message into alpha exponent sums for the generator polynomial alphas. To do that, we transform the byte into it's alpha exponent value according to the table.
{
GENERATOR_A%A_Index% := Mod(GENERATOR_A%A_Index% + AntilogTable[BYTE_1_OF_MESSAGE_POLYNOMIAL], 255)
}
Loop % NUMBER_OF_ECW + NUMBER_OF_MESSAGE_BYTES
{
GENERATOR_A%A_Index% := LogTable[GENERATOR_A%A_Index%] ; This will revert the alpha notation to the X multiplier. End of step 1a.
}
; Step b - XOR the result with the message polynomial (XOR with Zero for the lacking generator bytes and vice versa).
NEW_MESSAGE_LIST := ""
Loop % NUMBER_OF_ECW + NUMBER_OF_MESSAGE_BYTES
{
NEXT_ITERATION := A_Index + 1
BYTE_%A_INDEX%_OF_MESSAGE_POLYNOMIAL := ((GENERATOR_A%NEXT_ITERATION% > 0) ? (GENERATOR_A%NEXT_ITERATION%) : (0)) ^ ((BYTE_%NEXT_ITERATION%_OF_MESSAGE_POLYNOMIAL > 0) ? (BYTE_%NEXT_ITERATION%_OF_MESSAGE_POLYNOMIAL) : (0))
MESSAGE_X%A_Index% := (NUMBER_OF_ECW + NUMBER_OF_MESSAGE_BYTES) - A_Index + NUMBER_OF_ECW ; Here we create the exponents of X in the Message Polynomial.
}
GENERATOR_FIRST--
Loop % NUMBER_OF_ECW + NUMBER_OF_MESSAGE_BYTES
{
GENERATOR_X%A_Index% := GENERATOR_FIRST - A_Index + 15
}
}
ERROR_CORRECTION_CODEWORDS_%GROUP%_%BLOCK% := ""
ERROR_CORRECTION_CODEWORDS_%GROUP%_%BLOCK% := object()
Loop % NUMBER_OF_ECW + 1 ; Retrieve the Error Correction Codewords to return to the caller.
{
ERROR_CORRECTION_CODEWORDS_%GROUP%_%BLOCK%[A_Index] := BYTE_%A_INDEX%_OF_MESSAGE_POLYNOMIAL
}
Loop % NUMBER_OF_ECW + NUMBER_OF_MESSAGE_BYTES + 2 ; Free the message polynomial bytes for future use.
{
BYTE_%A_Index%_OF_MESSAGE_POLYNOMIAL := "", MESSAGE_X%A_Index% := "", GENERATOR_X%A_Index% := "", GENERATOR_A%A_Index% := ""
}
NUMBER_OF_MESSAGE_BYTES := "", GENERATOR_FIRST := "", NEXT_ITERATION := ""
}
Return
GENERATE_MATRIX(FINAL_MESSAGE, CHOOSEN_VERSION, CHOOSEN_ERROR_CORRECTION_LEVEL)
;Brief note:
; Here is the idea. Add all bits of CW + ECW, than apply masks and only than add the function patterns and the reserved areas (so that you can evaluate the mask) the last being all light color modules.
{
Global
MATRIX_UNMASKED := object()
MATRIX_DIMENSIONS := 17 + (CHOOSEN_VERSION * 4) ; First, we set the matrix dimensions. Since matrix dimensions start on 21 x 21 modules for V1 and increase by 4 modules on every subsequent version.
CURRENT_ROW := 1, COUNTER := 0
While (COUNTER < (MATRIX_DIMENSIONS**2 - MATRIX_DIMENSIONS)) ; We access each of the rows by the formula MATRIX_DIMENSIONS + 1 - CURRENT_ROW. Since the 7th column is entirely skipped before we enter it (because it belongs to a timing pattern that holds the exception regarding the writing algorithm)
{
CURRENT_COLUMN++
If (CURRENT_ROW = MATRIX_DIMENSIONS + 1) ; If this condition is met, we have left the below loop by the means of exceeding the upper limits of the matrix.
{
CURRENT_ROW := MATRIX_DIMENSIONS, CURRENT_COLUMN++
}
If (CURRENT_ROW = 0) ; If this condition is met, we have left the below loop by the means of exceeding the bottom limits of the matrix.
{
CURRENT_ROW := 1, CURRENT_COLUMN++
}
If (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN = 7) ; If this condition is met, we have reached the vertical timing pattern, which holds an exception to the writing algorithm, so we have to skipp writing to that column entirely and move the message writing position as though.
{
CURRENT_COLUMN++
}
While ((CURRENT_ROW <= MATRIX_DIMENSIONS) AND (CURRENT_ROW > 0) AND (CURRENT_COLUMN <= MATRIX_DIMENSIONS)) ; And than we access each of the individual modules (or the columns of individual rows). We access the columns by the formula MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN
{
COUNTER++
NOT_WRITE := 0
; Now to check if the current module address belongs to a function finder pattern.
; First, we check if the current module address reffers to a module located in the right-uppermost function finder pattern.
If ((MATRIX_DIMENSIONS + 1 - CURRENT_ROW <= 9) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 9)) ; At least 9 modules from the top and 9 modules from the left limits of the matrixes: all module addresses that satisfy these conditions are in the left-uppermost function finder pattern.
{
NOT_WRITE := 1
}
If ((MATRIX_DIMENSIONS + 1 - CURRENT_ROW <= 9) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= MATRIX_DIMENSIONS - 7)) ; At least 9 modules from the top and 8 from the right limits of the matrixes: all module addresses that satisfy these conditions are in the right-uppermost function finder pattern.
{
NOT_WRITE := 1
}
If ((MATRIX_DIMENSIONS + 1 - CURRENT_ROW >= MATRIX_DIMENSIONS - 7) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 9)) ; At least 8 modules from the base and 9 modules from the left limits of the matrixes: all module addresses that satisfy these conditions are in the left-bottommost function finder pattern.
{
NOT_WRITE := 1
}
; Now to check if the current module address belongs to a version information area (these exist only on version 7 or greater QR Matrixes)
If (CHOOSEN_VERSION >= 7)
{
If ((MATRIX_DIMENSIONS + 1 - CURRENT_ROW <= 6) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= MATRIX_DIMENSIONS - 10)) ; Between 9 to 11 modules from the right and 1 to 6 modules from the top limits of the matrixes: all module addresses that satisfy these conditions are located in the top-rightmost version information area, which exists only for versions 7 and higher.
{
NOT_WRITE := 1
}
If ((MATRIX_DIMENSIONS + 1 - CURRENT_ROW >= MATRIX_DIMENSIONS - 10) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 6)) ; Between 9 to the 11 modules from the bottom and 1 to 6 modules from the left limits of the matrixes: all module addresses that satisfy these conditions are located in the bottom-leftmost version information area, which exists only for versions 7 and higher.
{
NOT_WRITE := 1
}
}
; Now to check if the current module address belongs to a function ALIGNMENT pattern.
; We start off creating a string with the addresses for the upper-left modules of the alignment patterns of the choosen version.
; Version 1 Matrixes don't have any alignment patterns.
ALIGNMENT_LOCATIONS := "" ; We start off erasing this variable just to make sure it starts off empty.
% ((CHOOSEN_VERSION = 2) ? (ALIGNMENT_LOCATIONS := "17x17") : ("")), ((CHOOSEN_VERSION = 3) ? (ALIGNMENT_LOCATIONS := "21x21") : ("")), ((CHOOSEN_VERSION = 4) ? (ALIGNMENT_LOCATIONS := "25x25") : ("")), ((CHOOSEN_VERSION = 5) ? (ALIGNMENT_LOCATIONS := "29x29") : ("")), ((CHOOSEN_VERSION = 6) ? (ALIGNMENT_LOCATIONS := "33x33") : (""))
% ((CHOOSEN_VERSION = 7) ? (ALIGNMENT_LOCATIONS := "5x21|21x5|21x21|21x37|37x21|37x37") : ("")), ((CHOOSEN_VERSION = 8) ? (ALIGNMENT_LOCATIONS := "5x23|23x5|23x23|23x41|41x23|41x41") : ("")), ((CHOOSEN_VERSION = 9) ? (ALIGNMENT_LOCATIONS := "5x25|25x5|25x25|25x45|45x25|45x45") : ("")), ((CHOOSEN_VERSION = 10) ? (ALIGNMENT_LOCATIONS := "5x27|27x5|27x27|27x49|49x27|49x49") : ("")), ((CHOOSEN_VERSION = 11) ? (ALIGNMENT_LOCATIONS := "5x29|29x5|29x29|29x53|53x29|53x53") : ("")), ((CHOOSEN_VERSION = 12) ? (ALIGNMENT_LOCATIONS := "5x31|31x5|31x31|31x57|57x31|57x57") : ("")), ((CHOOSEN_VERSION = 13) ? (ALIGNMENT_LOCATIONS := "5x33|33x5|33x33|33x61|61x33|61x61") : (""))
% ((CHOOSEN_VERSION = 14) ? (ALIGNMENT_LOCATIONS := "5x25|5x45|25x5|25x25|25x45|25x65|45x5|45x25|45x45|45x65|65x25|65x45|65x65") : ("")), ((CHOOSEN_VERSION = 15) ? (ALIGNMENT_LOCATIONS := "5x25|5x47|25x5|25x25|25x47|25x69|47x5|47x25|47x47|47x69|69x25|69x47|69x69") : ("")), ((CHOOSEN_VERSION = 16) ? (ALIGNMENT_LOCATIONS := "5x25|5x49|25x5|25x25|25x49|25x73|49x5|49x25|49x49|49x73|73x25|73x49|73x73") : ("")), ((CHOOSEN_VERSION = 17) ? (ALIGNMENT_LOCATIONS := "5x29|5x53|29x5|29x29|29x53|29x77|53x5|53x29|53x53|53x77|77x29|77x53|77x77") : ("")), ((CHOOSEN_VERSION = 18) ? (ALIGNMENT_LOCATIONS := "5x29|5x55|29x5|29x29|29x55|29x81|55x5|55x29|55x55|55x81|81x29|81x55|81x81") : ("")), ((CHOOSEN_VERSION = 19) ? (ALIGNMENT_LOCATIONS := "5x29|5x57|29x5|29x29|29x57|29x85|57x5|57x29|57x57|57x85|85x29|85x57|85x85") : ("")), ((CHOOSEN_VERSION = 20) ? (ALIGNMENT_LOCATIONS := "5x33|5x61|33x5|33x33|33x61|33x89|61x5|61x33|61x61|61x89|89x33|89x61|89x89") : (""))
% ((CHOOSEN_VERSION = 21) ? (ALIGNMENT_LOCATIONS := "5x27|5x49|5x71|27x5|27x27|27x49|27x71|27x93|49x5|49x27|49x49|49x71|49x93|71x5|71x27|71x49|71x71|71x93|93x27|93x49|93x71|93x93") : ("")), ((CHOOSEN_VERSION = 22) ? (ALIGNMENT_LOCATIONS := "5x25|5x49|5x73|25x5|25x25|25x49|25x73|25x97|49x5|49x25|49x49|49x73|49x97|73x5|73x25|73x49|73x73|73x97|97x25|97x49|97x73|97x97") : ("")), ((CHOOSEN_VERSION = 23) ? (ALIGNMENT_LOCATIONS := "5x29|5x53|5x77|29x5|29x29|29x53|29x77|29x101|53x5|53x29|53x53|53x77|53x101|77x5|77x29|77x53|77x77|77x101|101x29|101x53|101x77|101x101") : ("")), ((CHOOSEN_VERSION = 24) ? (ALIGNMENT_LOCATIONS := "5x27|5x53|5x79|27x5|27x27|27x53|27x79|27x105|53x5|53x27|53x53|53x79|53x105|79x5|79x27|79x53|79x79|79x105|105x27|105x53|105x79|105x105") : ("")), ((CHOOSEN_VERSION = 25) ? (ALIGNMENT_LOCATIONS := "5x31|5x57|5x83|31x5|31x31|31x57|31x83|31x109|57x5|57x31|57x57|57x83|57x109|83x5|83x31|83x57|83x83|83x109|109x31|109x57|109x83|109x109") : ("")), ((CHOOSEN_VERSION = 26) ? (ALIGNMENT_LOCATIONS := "5x29|5x57|5x85|29x5|29x29|29x57|29x85|29x113|57x5|57x29|57x57|57x85|57x113|85x5|85x29|85x57|85x85|85x113|113x29|113x57|113x85|113x113") : ("")), ((CHOOSEN_VERSION = 27) ? (ALIGNMENT_LOCATIONS := "5x33|5x61|5x89|33x5|33x33|33x61|33x89|33x117|61x5|61x33|61x61|61x89|61x117|89x5|89x33|89x61|89x89|89x117|117x33|117x61|117x89|117x117") : (""))
% ((CHOOSEN_VERSION = 28) ? (ALIGNMENT_LOCATIONS := "5x25|5x49|5x73|5x97|25x5|25x25|25x49|25x73|25x97|25x121|49x5|49x25|49x49|49x73|49x97|49x121|73x5|73x25|73x49|73x73|73x97|73x121|97x5|97x25|97x49|97x73|97x97|97x121|121x25|121x49|121x73|121x97|121x121") : ("")), ((CHOOSEN_VERSION = 29) ? (ALIGNMENT_LOCATIONS := "5x29|5x53|5x77|5x101|29x5|29x29|29x53|29x77|29x101|29x125|53x5|53x29|53x53|53x77|53x101|53x125|77x5|77x29|77x53|77x77|77x101|77x125|101x5|101x29|101x53|101x77|101x101|101x125|125x29|125x53|125x77|125x101|125x125") : ("")), ((CHOOSEN_VERSION = 30) ? (ALIGNMENT_LOCATIONS := "5x25|5x51|5x77|5x103|25x5|25x25|25x51|25x77|25x103|25x129|51x5|51x25|51x51|51x77|51x103|51x129|77x5|77x25|77x51|77x77|77x103|77x129|103x5|103x25|103x51|103x77|103x103|103x129|129x25|129x51|129x77|129x103|129x129") : ("")), ((CHOOSEN_VERSION = 31) ? (ALIGNMENT_LOCATIONS := "5x29|5x55|5x81|5x107|29x5|29x29|29x55|29x81|29x107|29x133|55x5|55x29|55x55|55x81|55x107|55x133|81x5|81x29|81x55|81x81|81x107|81x133|107x5|107x29|107x55|107x81|107x107|107x133|133x29|133x55|133x81|133x107|133x133") : ("")), ((CHOOSEN_VERSION = 32) ? (ALIGNMENT_LOCATIONS := "5x33|5x59|5x85|5x111|33x5|33x33|33x59|33x85|33x111|33x137|59x5|59x33|59x59|59x85|59x111|59x137|85x5|85x33|85x59|85x85|85x111|85x137|111x5|111x33|111x59|111x85|111x111|111x137|137x33|137x59|137x85|137x111|137x137") : ("")), ((CHOOSEN_VERSION = 33) ? (ALIGNMENT_LOCATIONS := "5x29|5x57|5x85|5x113|29x5|29x29|29x57|29x85|29x113|29x141|57x5|57x29|57x57|57x85|57x113|57x141|85x5|85x29|85x57|85x85|85x113|85x141|113x5|113x29|113x57|113x85|113x113|113x141|141x29|141x57|141x85|141x113|141x141") : ("")), ((CHOOSEN_VERSION = 34) ? (ALIGNMENT_LOCATIONS := "5x33|5x61|5x89|5x117|33x5|33x33|33x61|33x89|33x117|33x145|61x5|61x33|61x61|61x89|61x117|61x145|89x5|89x33|89x61|89x89|89x117|89x145|117x5|117x33|117x61|117x89|117x117|117x145|145x33|145x61|145x89|145x117|145x145") : (""))
% ((CHOOSEN_VERSION = 35) ? (ALIGNMENT_LOCATIONS := "5x29|5x53|5x77|5x101|5x125|29x5|29x29|29x53|29x77|29x101|29x125|29x149|53x5|53x29|53x53|53x77|53x101|53x125|53x149|77x5|77x29|77x53|77x77|77x101|77x125|77x149|101x5|101x29|101x53|101x77|101x101|101x125|101x149|125x5|125x29|125x53|125x77|125x101|125x125|125x149|149x29|149x53|149x77|149x101|149x125|149x149") : ("")), ((CHOOSEN_VERSION = 36) ? (ALIGNMENT_LOCATIONS := "5x23|5x49|5x75|5x101|5x127|23x5|23x23|23x49|23x75|23x101|23x127|23x153|49x5|49x23|49x49|49x75|49x101|49x127|49x153|75x5|75x23|75x49|75x75|75x101|75x127|75x153|101x5|101x23|101x49|101x75|101x101|101x127|101x153|127x5|127x23|127x49|127x75|127x101|127x127|127x153|153x23|153x49|153x75|153x101|153x127|153x153") : ("")), ((CHOOSEN_VERSION = 37) ? (ALIGNMENT_LOCATIONS := "5x27|5x53|5x79|5x105|5x131|27x5|27x27|27x53|27x79|27x105|27x131|27x157|53x5|53x27|53x53|53x79|53x105|53x131|53x157|79x5|79x27|79x53|79x79|79x105|79x131|79x157|105x5|105x27|105x53|105x79|105x105|105x131|105x157|131x5|131x27|131x53|131x79|131x105|131x131|131x157|157x27|157x53|157x79|157x105|157x131|157x157") : ("")), ((CHOOSEN_VERSION = 38) ? (ALIGNMENT_LOCATIONS := "5x31|5x57|5x83|5x109|5x135|31x5|31x31|31x57|31x83|31x109|31x135|31x161|57x5|57x31|57x57|57x83|57x109|57x135|57x161|83x5|83x31|83x57|83x83|83x109|83x135|83x161|109x5|109x31|109x57|109x83|109x109|109x135|109x161|135x5|135x31|135x57|135x83|135x109|135x135|135x161|161x31|161x57|161x83|161x109|161x135|161x161") : ("")), ((CHOOSEN_VERSION = 39) ? (ALIGNMENT_LOCATIONS := "5x25|5x53|5x81|5x109|5x137|25x5|25x25|25x53|25x81|25x109|25x137|25x165|53x5|53x25|53x53|53x81|53x109|53x137|53x165|81x5|81x25|81x53|81x81|81x109|81x137|81x165|109x5|109x25|109x53|109x81|109x109|109x137|109x165|137x5|137x25|137x53|137x81|137x109|137x137|137x165|165x25|165x53|165x81|165x109|165x137|165x165") : ("")), ((CHOOSEN_VERSION = 40) ? (ALIGNMENT_LOCATIONS := "5x29|5x57|5x85|5x113|5x141|29x5|29x29|29x57|29x85|29x113|29x141|29x169|57x5|57x29|57x57|57x85|57x113|57x141|57x169|85x5|85x29|85x57|85x85|85x113|85x141|85x169|113x5|113x29|113x57|113x85|113x113|113x141|113x169|141x5|141x29|141x57|141x85|141x113|141x141|141x169|169x29|169x57|169x85|169x113|169x141|169x169") : (""))
; Now, we separate the strings into the individual addresses
ALIGNMENT_INDIVIDUAL_COORDINATES_ := ""
StringSplit, ALIGNMENT_INDIVIDUAL_COORDINATES_, ALIGNMENT_LOCATIONS, "|"
Loop % ALIGNMENT_INDIVIDUAL_COORDINATES_0
{
INDIVIDUAL_ALIGNMENT_COORDS_ := ""
StringSplit, INDIVIDUAL_ALIGNMENT_COORDS_, ALIGNMENT_INDIVIDUAL_COORDINATES_%A_Index%, x
If ((MATRIX_DIMENSIONS + 1 - CURRENT_ROW >= INDIVIDUAL_ALIGNMENT_COORDS_1) AND (MATRIX_DIMENSIONS + 1 - CURRENT_ROW <= INDIVIDUAL_ALIGNMENT_COORDS_1 + 4) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= INDIVIDUAL_ALIGNMENT_COORDS_2) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= INDIVIDUAL_ALIGNMENT_COORDS_2 + 4)) ; If these conditons are met, we are at an alignment patterns area.
{
NOT_WRITE := 1
}
}
; Now to check if the current module address belongs to a timing pattern.
; The timing patterns are always located in the 7th row and the 7th column.
if (MATRIX_DIMENSIONS + 1 - CURRENT_ROW = 7)
{
NOT_WRITE := 1
}
if (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN = 7)
{
NOT_WRITE := 1
}
; CODE TO MOVE IF WE ARE NOT IN ANY FUNCTION PATTERN OR RESERVED AREA.
; Now things get a little tricky. QR Code matrixes are always odd numbered dimensioned. This means that the column we start off positiong the EC + ECW is always an even numbered columm. Whenever we are at an odd number column, the next address to visit is located leftwards 1 position. Whenever we are at an even number columns, the next address to visit is located rightwards 1 and uppwards 1, except if we reach the end of the column, where it will be leftwards 1 and modify the direction of the movements to be leftwards 1 at an even numbered columns and rightwards 1 downwards 1 at an odd column.
If (NOT_WRITE = 0)
{
StringLeft, BIT_TO_WRITE, FINAL_MESSAGE, 1
StringTrimLeft, FINAL_MESSAGE, FINAL_MESSAGE, 1
MATRIX_UNMASKED[MATRIX_DIMENSIONS + 1 - CURRENT_ROW, MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN] := BIT_TO_WRITE
}
If (((Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 1) OR (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 0)) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= 8))
CURRENT_WRITING_DIRECTION := "UP"
If (((Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 3) OR (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 2)) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= 8))
CURRENT_WRITING_DIRECTION := "DOWN"
If (((Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 1) OR (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 2)) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 6))
CURRENT_WRITING_DIRECTION := "DOWN"
If (((Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 3) OR (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN, 4) = 0)) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 6))
CURRENT_WRITING_DIRECTION := "UP"
If (CURRENT_WRITING_DIRECTION = "UP")
{
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 1) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= 8)
{
CURRENT_COLUMN++
Continue
}
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 1) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 6)
{
CURRENT_COLUMN--, CURRENT_ROW++
Continue
}
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 0) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= 8)
{
CURRENT_COLUMN--, CURRENT_ROW++
Continue
}
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 0) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 6)
{
CURRENT_COLUMN++
Continue
}
}
If (CURRENT_WRITING_DIRECTION = "DOWN")
{
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 1) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= 8)
{
CURRENT_COLUMN++
Continue
}
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 1) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 6)
{
CURRENT_COLUMN--, CURRENT_ROW--
Continue
}
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 0) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN >= 8)
{
CURRENT_COLUMN --, CURRENT_ROW--
Continue
}
If (Mod(MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN,2) = 0) AND (MATRIX_DIMENSIONS + 1 - CURRENT_COLUMN <= 6)
{
CURRENT_COLUMN++
Continue
}
}
}
}
; Once all the CW+ECW bits have been added, we now apply the masks. Each mask goes on one copy of the unmasked matrix.
; First, make a copy of the unmasked version.
MATRIX_MASK_ONE := Object(), MATRIX_MASK_TWO := Object(), MATRIX_MASK_THREE := Object(), MATRIX_MASK_FOUR := Object(), MATRIX_MASK_FIVE := Object(), MATRIX_MASK_SIX := Object(), MATRIX_MASK_SEVEN := Object(), MATRIX_MASK_EIGHT := Object()
Loop % MATRIX_DIMENSIONS ; One for every row
{
CURRENT_ROW := A_Index
Loop % MATRIX_DIMENSIONS ; One for every column
{
MATRIX_MASK_ONE[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
MATRIX_MASK_TWO[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
MATRIX_MASK_THREE[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
MATRIX_MASK_FOUR[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
MATRIX_MASK_FIVE[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
MATRIX_MASK_SIX[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
MATRIX_MASK_SEVEN[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
MATRIX_MASK_EIGHT[CURRENT_ROW, A_Index] := MATRIX_UNMASKED[CURRENT_ROW, A_Index]
}
}
; And now we apply each mask to the copies we created previously.
; Note: since the specs define start row and column addresses as 0 (rather than at 1), the calculations must subtract 1. The matrix objects start at 1, so they won't be affected.
Loop % MATRIX_DIMENSIONS ; One for every row
{
CURRENT_ROW := A_Index
Loop % MATRIX_DIMENSIONS ; One for every column
{
If (Mod((CURRENT_ROW-1) + (A_Index-1), 2) = 0) ; Mask one: Switch if (row + column) mod 2 == 0
{
MATRIX_MASK_ONE[CURRENT_ROW, A_Index] := !(MATRIX_MASK_ONE[CURRENT_ROW, A_Index])
}
If (Mod((CURRENT_ROW-1), 2) = 0) ; Mask two: Switch if (row) mod 2 == 0
{
MATRIX_MASK_TWO[CURRENT_ROW, A_Index] := !(MATRIX_MASK_TWO[CURRENT_ROW, A_Index])
}
If (Mod((A_Index-1), 3) = 0) ; Mask three: Switch if (column) mod 3 == 0
{
MATRIX_MASK_THREE[CURRENT_ROW, A_Index] := !(MATRIX_MASK_THREE[CURRENT_ROW, A_Index])
}