1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Class Version |
4
|
|
|
* |
5
|
|
|
* @created 19.11.2020 |
6
|
|
|
* @author smiley <[email protected]> |
7
|
|
|
* @copyright 2020 smiley |
8
|
|
|
* @license MIT |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace chillerlan\QRCode\Common; |
12
|
|
|
|
13
|
|
|
use chillerlan\QRCode\QRCodeException; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* |
17
|
|
|
*/ |
18
|
|
|
final class Version{ |
19
|
|
|
|
20
|
|
|
public const AUTO = -1; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* ISO/IEC 18004:2000 Annex E, Table E.1 - Row/column coordinates of center module of Alignment Patterns |
24
|
|
|
* |
25
|
|
|
* version -> pattern |
26
|
|
|
* |
27
|
|
|
* @var int[][] |
28
|
|
|
*/ |
29
|
|
|
private const ALIGNMENT_PATTERN = [ |
30
|
|
|
1 => [], |
31
|
|
|
2 => [6, 18], |
32
|
|
|
3 => [6, 22], |
33
|
|
|
4 => [6, 26], |
34
|
|
|
5 => [6, 30], |
35
|
|
|
6 => [6, 34], |
36
|
|
|
7 => [6, 22, 38], |
37
|
|
|
8 => [6, 24, 42], |
38
|
|
|
9 => [6, 26, 46], |
39
|
|
|
10 => [6, 28, 50], |
40
|
|
|
11 => [6, 30, 54], |
41
|
|
|
12 => [6, 32, 58], |
42
|
|
|
13 => [6, 34, 62], |
43
|
|
|
14 => [6, 26, 46, 66], |
44
|
|
|
15 => [6, 26, 48, 70], |
45
|
|
|
16 => [6, 26, 50, 74], |
46
|
|
|
17 => [6, 30, 54, 78], |
47
|
|
|
18 => [6, 30, 56, 82], |
48
|
|
|
19 => [6, 30, 58, 86], |
49
|
|
|
20 => [6, 34, 62, 90], |
50
|
|
|
21 => [6, 28, 50, 72, 94], |
51
|
|
|
22 => [6, 26, 50, 74, 98], |
52
|
|
|
23 => [6, 30, 54, 78, 102], |
53
|
|
|
24 => [6, 28, 54, 80, 106], |
54
|
|
|
25 => [6, 32, 58, 84, 110], |
55
|
|
|
26 => [6, 30, 58, 86, 114], |
56
|
|
|
27 => [6, 34, 62, 90, 118], |
57
|
|
|
28 => [6, 26, 50, 74, 98, 122], |
58
|
|
|
29 => [6, 30, 54, 78, 102, 126], |
59
|
|
|
30 => [6, 26, 52, 78, 104, 130], |
60
|
|
|
31 => [6, 30, 56, 82, 108, 134], |
61
|
|
|
32 => [6, 34, 60, 86, 112, 138], |
62
|
|
|
33 => [6, 30, 58, 86, 114, 142], |
63
|
|
|
34 => [6, 34, 62, 90, 118, 146], |
64
|
|
|
35 => [6, 30, 54, 78, 102, 126, 150], |
65
|
|
|
36 => [6, 24, 50, 76, 102, 128, 154], |
66
|
|
|
37 => [6, 28, 54, 80, 106, 132, 158], |
67
|
|
|
38 => [6, 32, 58, 84, 110, 136, 162], |
68
|
|
|
39 => [6, 26, 54, 82, 110, 138, 166], |
69
|
|
|
40 => [6, 30, 58, 86, 114, 142, 170], |
70
|
|
|
]; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* ISO/IEC 18004:2000 Annex D, Table D.1 - Version information bit stream for each version |
74
|
|
|
* |
75
|
|
|
* no version pattern for QR Codes < 7 |
76
|
|
|
* |
77
|
|
|
* @var int[] |
78
|
|
|
*/ |
79
|
|
|
private const VERSION_PATTERN = [ |
80
|
|
|
7 => 0b000111110010010100, |
81
|
|
|
8 => 0b001000010110111100, |
82
|
|
|
9 => 0b001001101010011001, |
83
|
|
|
10 => 0b001010010011010011, |
84
|
|
|
11 => 0b001011101111110110, |
85
|
|
|
12 => 0b001100011101100010, |
86
|
|
|
13 => 0b001101100001000111, |
87
|
|
|
14 => 0b001110011000001101, |
88
|
|
|
15 => 0b001111100100101000, |
89
|
|
|
16 => 0b010000101101111000, |
90
|
|
|
17 => 0b010001010001011101, |
91
|
|
|
18 => 0b010010101000010111, |
92
|
|
|
19 => 0b010011010100110010, |
93
|
|
|
20 => 0b010100100110100110, |
94
|
|
|
21 => 0b010101011010000011, |
95
|
|
|
22 => 0b010110100011001001, |
96
|
|
|
23 => 0b010111011111101100, |
97
|
|
|
24 => 0b011000111011000100, |
98
|
|
|
25 => 0b011001000111100001, |
99
|
|
|
26 => 0b011010111110101011, |
100
|
|
|
27 => 0b011011000010001110, |
101
|
|
|
28 => 0b011100110000011010, |
102
|
|
|
29 => 0b011101001100111111, |
103
|
|
|
30 => 0b011110110101110101, |
104
|
|
|
31 => 0b011111001001010000, |
105
|
|
|
32 => 0b100000100111010101, |
106
|
|
|
33 => 0b100001011011110000, |
107
|
|
|
34 => 0b100010100010111010, |
108
|
|
|
35 => 0b100011011110011111, |
109
|
|
|
36 => 0b100100101100001011, |
110
|
|
|
37 => 0b100101010000101110, |
111
|
|
|
38 => 0b100110101001100100, |
112
|
|
|
39 => 0b100111010101000001, |
113
|
|
|
40 => 0b101000110001101001, |
114
|
|
|
]; |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* ISO/IEC 18004:2000 Tables 13-22 |
118
|
|
|
* |
119
|
|
|
* @see http://www.thonky.com/qr-code-tutorial/error-correction-table |
120
|
|
|
*/ |
121
|
|
|
private const RSBLOCKS = [ |
122
|
|
|
1 => [[ 7, [[ 1, 19], [ 0, 0]]], [10, [[ 1, 16], [ 0, 0]]], [13, [[ 1, 13], [ 0, 0]]], [17, [[ 1, 9], [ 0, 0]]]], |
123
|
|
|
2 => [[10, [[ 1, 34], [ 0, 0]]], [16, [[ 1, 28], [ 0, 0]]], [22, [[ 1, 22], [ 0, 0]]], [28, [[ 1, 16], [ 0, 0]]]], |
124
|
|
|
3 => [[15, [[ 1, 55], [ 0, 0]]], [26, [[ 1, 44], [ 0, 0]]], [18, [[ 2, 17], [ 0, 0]]], [22, [[ 2, 13], [ 0, 0]]]], |
125
|
|
|
4 => [[20, [[ 1, 80], [ 0, 0]]], [18, [[ 2, 32], [ 0, 0]]], [26, [[ 2, 24], [ 0, 0]]], [16, [[ 4, 9], [ 0, 0]]]], |
126
|
|
|
5 => [[26, [[ 1, 108], [ 0, 0]]], [24, [[ 2, 43], [ 0, 0]]], [18, [[ 2, 15], [ 2, 16]]], [22, [[ 2, 11], [ 2, 12]]]], |
127
|
|
|
6 => [[18, [[ 2, 68], [ 0, 0]]], [16, [[ 4, 27], [ 0, 0]]], [24, [[ 4, 19], [ 0, 0]]], [28, [[ 4, 15], [ 0, 0]]]], |
128
|
|
|
7 => [[20, [[ 2, 78], [ 0, 0]]], [18, [[ 4, 31], [ 0, 0]]], [18, [[ 2, 14], [ 4, 15]]], [26, [[ 4, 13], [ 1, 14]]]], |
129
|
|
|
8 => [[24, [[ 2, 97], [ 0, 0]]], [22, [[ 2, 38], [ 2, 39]]], [22, [[ 4, 18], [ 2, 19]]], [26, [[ 4, 14], [ 2, 15]]]], |
130
|
|
|
9 => [[30, [[ 2, 116], [ 0, 0]]], [22, [[ 3, 36], [ 2, 37]]], [20, [[ 4, 16], [ 4, 17]]], [24, [[ 4, 12], [ 4, 13]]]], |
131
|
|
|
10 => [[18, [[ 2, 68], [ 2, 69]]], [26, [[ 4, 43], [ 1, 44]]], [24, [[ 6, 19], [ 2, 20]]], [28, [[ 6, 15], [ 2, 16]]]], |
132
|
|
|
11 => [[20, [[ 4, 81], [ 0, 0]]], [30, [[ 1, 50], [ 4, 51]]], [28, [[ 4, 22], [ 4, 23]]], [24, [[ 3, 12], [ 8, 13]]]], |
133
|
|
|
12 => [[24, [[ 2, 92], [ 2, 93]]], [22, [[ 6, 36], [ 2, 37]]], [26, [[ 4, 20], [ 6, 21]]], [28, [[ 7, 14], [ 4, 15]]]], |
134
|
|
|
13 => [[26, [[ 4, 107], [ 0, 0]]], [22, [[ 8, 37], [ 1, 38]]], [24, [[ 8, 20], [ 4, 21]]], [22, [[12, 11], [ 4, 12]]]], |
135
|
|
|
14 => [[30, [[ 3, 115], [ 1, 116]]], [24, [[ 4, 40], [ 5, 41]]], [20, [[11, 16], [ 5, 17]]], [24, [[11, 12], [ 5, 13]]]], |
136
|
|
|
15 => [[22, [[ 5, 87], [ 1, 88]]], [24, [[ 5, 41], [ 5, 42]]], [30, [[ 5, 24], [ 7, 25]]], [24, [[11, 12], [ 7, 13]]]], |
137
|
|
|
16 => [[24, [[ 5, 98], [ 1, 99]]], [28, [[ 7, 45], [ 3, 46]]], [24, [[15, 19], [ 2, 20]]], [30, [[ 3, 15], [13, 16]]]], |
138
|
|
|
17 => [[28, [[ 1, 107], [ 5, 108]]], [28, [[10, 46], [ 1, 47]]], [28, [[ 1, 22], [15, 23]]], [28, [[ 2, 14], [17, 15]]]], |
139
|
|
|
18 => [[30, [[ 5, 120], [ 1, 121]]], [26, [[ 9, 43], [ 4, 44]]], [28, [[17, 22], [ 1, 23]]], [28, [[ 2, 14], [19, 15]]]], |
140
|
|
|
19 => [[28, [[ 3, 113], [ 4, 114]]], [26, [[ 3, 44], [11, 45]]], [26, [[17, 21], [ 4, 22]]], [26, [[ 9, 13], [16, 14]]]], |
141
|
|
|
20 => [[28, [[ 3, 107], [ 5, 108]]], [26, [[ 3, 41], [13, 42]]], [30, [[15, 24], [ 5, 25]]], [28, [[15, 15], [10, 16]]]], |
142
|
|
|
21 => [[28, [[ 4, 116], [ 4, 117]]], [26, [[17, 42], [ 0, 0]]], [28, [[17, 22], [ 6, 23]]], [30, [[19, 16], [ 6, 17]]]], |
143
|
|
|
22 => [[28, [[ 2, 111], [ 7, 112]]], [28, [[17, 46], [ 0, 0]]], [30, [[ 7, 24], [16, 25]]], [24, [[34, 13], [ 0, 0]]]], |
144
|
|
|
23 => [[30, [[ 4, 121], [ 5, 122]]], [28, [[ 4, 47], [14, 48]]], [30, [[11, 24], [14, 25]]], [30, [[16, 15], [14, 16]]]], |
145
|
|
|
24 => [[30, [[ 6, 117], [ 4, 118]]], [28, [[ 6, 45], [14, 46]]], [30, [[11, 24], [16, 25]]], [30, [[30, 16], [ 2, 17]]]], |
146
|
|
|
25 => [[26, [[ 8, 106], [ 4, 107]]], [28, [[ 8, 47], [13, 48]]], [30, [[ 7, 24], [22, 25]]], [30, [[22, 15], [13, 16]]]], |
147
|
|
|
26 => [[28, [[10, 114], [ 2, 115]]], [28, [[19, 46], [ 4, 47]]], [28, [[28, 22], [ 6, 23]]], [30, [[33, 16], [ 4, 17]]]], |
148
|
|
|
27 => [[30, [[ 8, 122], [ 4, 123]]], [28, [[22, 45], [ 3, 46]]], [30, [[ 8, 23], [26, 24]]], [30, [[12, 15], [28, 16]]]], |
149
|
|
|
28 => [[30, [[ 3, 117], [10, 118]]], [28, [[ 3, 45], [23, 46]]], [30, [[ 4, 24], [31, 25]]], [30, [[11, 15], [31, 16]]]], |
150
|
|
|
29 => [[30, [[ 7, 116], [ 7, 117]]], [28, [[21, 45], [ 7, 46]]], [30, [[ 1, 23], [37, 24]]], [30, [[19, 15], [26, 16]]]], |
151
|
|
|
30 => [[30, [[ 5, 115], [10, 116]]], [28, [[19, 47], [10, 48]]], [30, [[15, 24], [25, 25]]], [30, [[23, 15], [25, 16]]]], |
152
|
|
|
31 => [[30, [[13, 115], [ 3, 116]]], [28, [[ 2, 46], [29, 47]]], [30, [[42, 24], [ 1, 25]]], [30, [[23, 15], [28, 16]]]], |
153
|
|
|
32 => [[30, [[17, 115], [ 0, 0]]], [28, [[10, 46], [23, 47]]], [30, [[10, 24], [35, 25]]], [30, [[19, 15], [35, 16]]]], |
154
|
|
|
33 => [[30, [[17, 115], [ 1, 116]]], [28, [[14, 46], [21, 47]]], [30, [[29, 24], [19, 25]]], [30, [[11, 15], [46, 16]]]], |
155
|
|
|
34 => [[30, [[13, 115], [ 6, 116]]], [28, [[14, 46], [23, 47]]], [30, [[44, 24], [ 7, 25]]], [30, [[59, 16], [ 1, 17]]]], |
156
|
|
|
35 => [[30, [[12, 121], [ 7, 122]]], [28, [[12, 47], [26, 48]]], [30, [[39, 24], [14, 25]]], [30, [[22, 15], [41, 16]]]], |
157
|
|
|
36 => [[30, [[ 6, 121], [14, 122]]], [28, [[ 6, 47], [34, 48]]], [30, [[46, 24], [10, 25]]], [30, [[ 2, 15], [64, 16]]]], |
158
|
|
|
37 => [[30, [[17, 122], [ 4, 123]]], [28, [[29, 46], [14, 47]]], [30, [[49, 24], [10, 25]]], [30, [[24, 15], [46, 16]]]], |
159
|
|
|
38 => [[30, [[ 4, 122], [18, 123]]], [28, [[13, 46], [32, 47]]], [30, [[48, 24], [14, 25]]], [30, [[42, 15], [32, 16]]]], |
160
|
|
|
39 => [[30, [[20, 117], [ 4, 118]]], [28, [[40, 47], [ 7, 48]]], [30, [[43, 24], [22, 25]]], [30, [[10, 15], [67, 16]]]], |
161
|
|
|
40 => [[30, [[19, 118], [ 6, 119]]], [28, [[18, 47], [31, 48]]], [30, [[34, 24], [34, 25]]], [30, [[20, 15], [61, 16]]]], |
162
|
|
|
]; |
163
|
|
|
|
164
|
|
|
private const TOTAL_CODEWORDS = [ |
165
|
|
|
1 => 26, |
166
|
|
|
2 => 44, |
167
|
|
|
3 => 70, |
168
|
|
|
4 => 100, |
169
|
|
|
5 => 134, |
170
|
|
|
6 => 172, |
171
|
|
|
7 => 196, |
172
|
|
|
8 => 242, |
173
|
|
|
9 => 292, |
174
|
|
|
10 => 346, |
175
|
|
|
11 => 404, |
176
|
|
|
12 => 466, |
177
|
|
|
13 => 532, |
178
|
|
|
14 => 581, |
179
|
|
|
15 => 655, |
180
|
|
|
16 => 733, |
181
|
|
|
17 => 815, |
182
|
|
|
18 => 901, |
183
|
|
|
19 => 991, |
184
|
|
|
20 => 1085, |
185
|
|
|
21 => 1156, |
186
|
|
|
22 => 1258, |
187
|
|
|
23 => 1364, |
188
|
|
|
24 => 1474, |
189
|
|
|
25 => 1588, |
190
|
|
|
26 => 1706, |
191
|
|
|
27 => 1828, |
192
|
|
|
28 => 1921, |
193
|
|
|
29 => 2051, |
194
|
|
|
30 => 2185, |
195
|
|
|
31 => 2323, |
196
|
|
|
32 => 2465, |
197
|
|
|
33 => 2611, |
198
|
|
|
34 => 2761, |
199
|
|
|
35 => 2876, |
200
|
|
|
36 => 3034, |
201
|
|
|
37 => 3196, |
202
|
|
|
38 => 3362, |
203
|
|
|
39 => 3532, |
204
|
|
|
40 => 3706, |
205
|
|
|
]; |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* QR Code version number |
209
|
|
|
*/ |
210
|
|
|
private int $version; |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Version constructor. |
214
|
|
|
* |
215
|
|
|
* @throws \chillerlan\QRCode\QRCodeException |
216
|
|
|
*/ |
217
|
|
|
public function __construct(int $version){ |
218
|
|
|
|
219
|
|
|
if($version < 1 || $version > 40){ |
220
|
|
|
throw new QRCodeException('invalid version given'); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
$this->version = $version; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* returns the current version number as string |
228
|
|
|
*/ |
229
|
|
|
public function __toString():string{ |
230
|
|
|
return (string)$this->version; |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* returns the current version number |
235
|
|
|
*/ |
236
|
|
|
public function getVersionNumber():int{ |
237
|
|
|
return $this->version; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* the matrix size for the given version |
242
|
|
|
*/ |
243
|
|
|
public function getDimension():int{ |
244
|
|
|
return $this->version * 4 + 17; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* the version pattern for the given version |
249
|
|
|
*/ |
250
|
|
|
public function getVersionPattern():?int{ |
251
|
|
|
return self::VERSION_PATTERN[$this->version] ?? null; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* the alignment patterns for the current version |
256
|
|
|
* |
257
|
|
|
* @return int[] |
258
|
|
|
*/ |
259
|
|
|
public function getAlignmentPattern():array{ |
260
|
|
|
return self::ALIGNMENT_PATTERN[$this->version]; |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* returns ECC block information for the given $version and $eccLevel |
265
|
|
|
*/ |
266
|
|
|
public function getRSBlocks(EccLevel $eccLevel):array{ |
267
|
|
|
return self::RSBLOCKS[$this->version][$eccLevel->getOrdinal()]; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* returns the maximum codewords for the current version |
272
|
|
|
*/ |
273
|
|
|
public function getTotalCodewords():int{ |
274
|
|
|
return self::TOTAL_CODEWORDS[$this->version]; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
} |
278
|
|
|
|