Version::getAlignmentPattern()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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