Completed
Push — master ( 1a2d4b...99084f )
by smiley
03:12
created

QRCode::output()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
/**
3
 * Class QRCode
4
 *
5
 * @filesource   QRCode.php
6
 * @created      26.11.2015
7
 * @package      chillerlan\QRCode
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2015 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\QRCode;
14
15
use chillerlan\QRCode\Data\AlphaNum;
16
use chillerlan\QRCode\Data\Byte;
17
use chillerlan\QRCode\Data\Kanji;
18
use chillerlan\QRCode\Data\Number;
19
use chillerlan\QRCode\Output\QROutputInterface;
20
21
/**
22
 * @link https://github.com/kazuhikoarase/qrcode-generator/tree/master/php
23
 * @link http://www.thonky.com/qr-code-tutorial/
24
 */
25
class QRCode{
26
27
	/**
28
	 * API constants
29
	 */
30
	const OUTPUT_STRING_TEXT = 0;
31
	const OUTPUT_STRING_JSON = 1;
32
	const OUTPUT_STRING_HTML = 2;
33
34
	const OUTPUT_IMAGE_PNG = 'png';
35
	const OUTPUT_IMAGE_JPG = 'jpg';
36
	const OUTPUT_IMAGE_GIF = 'gif';
37
38
	const ERROR_CORRECT_LEVEL_L = 1; // 7%.
39
	const ERROR_CORRECT_LEVEL_M = 0; // 15%.
40
	const ERROR_CORRECT_LEVEL_Q = 3; // 25%.
41
	const ERROR_CORRECT_LEVEL_H = 2; // 30%.
42
43
	// max bits @ ec level L:07 M:15 Q:25 H:30 %
44
	const TYPE_01 =  1; //  152  128  104   72
45
	const TYPE_02 =  2; //  272  224  176  128
46
	const TYPE_03 =  3; //  440  352  272  208
47
	const TYPE_04 =  4; //  640  512  384  288
48
	const TYPE_05 =  5; //  864  688  496  368
49
	const TYPE_06 =  6; // 1088  864  608  480
50
	const TYPE_07 =  7; // 1248  992  704  528
51
	const TYPE_08 =  8; // 1552 1232  880  688
52
	const TYPE_09 =  9; // 1856 1456 1056  800
53
	const TYPE_10 = 10; // 2192 1728 1232  976
54
55
	/**
56
	 * @var array
57
	 */
58
	protected $matrix = [];
59
60
	/**
61
	 * @var int
62
	 */
63
	protected $pixelCount = 0;
64
65
	/**
66
	 * @var int
67
	 */
68
	protected $typeNumber;
69
70
	/**
71
	 * @var int
72
	 */
73
	protected $errorCorrectLevel;
74
75
	/**
76
	 * @var \chillerlan\QRCode\BitBuffer
77
	 */
78
	protected $bitBuffer;
79
80
	/**
81
	 * @var \chillerlan\QRCode\Data\QRDataInterface
82
	 */
83
	protected $qrDataInterface;
84
85
	/**
86
	 * @var \chillerlan\QRCode\Output\QROutputInterface
87
	 */
88
	protected $qrOutputInterface;
89
90
	/**
91
	 * QRCode constructor.
92
	 *
93
	 * @param string                                      $data
94
	 * @param \chillerlan\QRCode\Output\QROutputInterface $output
95
	 * @param \chillerlan\QRCode\QROptions|null           $options
96
	 */
97
	public function __construct($data, QROutputInterface $output, QROptions $options = null){
98
		$this->qrOutputInterface = $output;
99
		$this->bitBuffer = new BitBuffer;
100
		$this->setData($data, $options);
101
	}
102
103
	/**
104
	 * @param string                            $data
105
	 * @param \chillerlan\QRCode\QROptions|null $options
106
	 *
107
	 * @return $this
108
	 * @throws \chillerlan\QRCode\QRCodeException
109
	 */
110
	public function setData($data, QROptions $options = null){
111
		$data = trim($data);
112
113
		if(empty($data)){
114
			throw new QRCodeException('No data given.');
115
		}
116
117
		if(!$options instanceof QROptions){
118
			$options = new QROptions;
119
		}
120
121
		if(!in_array($options->errorCorrectLevel, QRConst::RSBLOCK, true)){
122
			throw new QRCodeException('Invalid error correct level: '.$options->errorCorrectLevel);
123
		}
124
125
		$this->errorCorrectLevel = $options->errorCorrectLevel;
126
127
		switch(true){
128
			case Util::isAlphaNum($data):
129
				$mode = Util::isNumber($data) ? QRConst::MODE_NUMBER : QRConst::MODE_ALPHANUM;
130
				break;
131
			case Util::isKanji($data):
132
				$mode = QRConst::MODE_KANJI;
133
				break;
134
			default:
135
				$mode = QRConst::MODE_BYTE;
136
				break;
137
		}
138
139
		$qrDataInterface = [
140
			QRConst::MODE_ALPHANUM => AlphaNum::class,
141
			QRConst::MODE_BYTE     => Byte::class,
142
			QRConst::MODE_KANJI    => Kanji::class,
143
			QRConst::MODE_NUMBER   => Number::class,
144
		][$mode];
145
146
		$this->qrDataInterface = new $qrDataInterface($data);
147
		$this->typeNumber = intval($options->typeNumber);
148
149
		if($this->typeNumber < 1 || $this->typeNumber > 10){
150
			$this->typeNumber = $this->getTypeNumber($mode);
151
		}
152
153
		return $this;
154
	}
155
156
	/**
157
	 * @param $mode
158
	 *
159
	 * @return int
160
	 * @throws \chillerlan\QRCode\QRCodeException
161
	 */
162
	protected function getTypeNumber($mode){
163
		$length = $this->qrDataInterface->dataLength;
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
164
165
		if($this->qrDataInterface->mode === QRConst::MODE_KANJI){
0 ignored issues
show
Bug introduced by
Accessing mode on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
166
			$length = floor($this->qrDataInterface->dataLength / 2);
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
167
		}
168
169
		foreach(range(1, 10) as $type){
170
			if($length <= Util::getMaxLength($type, $mode, $this->errorCorrectLevel)){
171
				return $type;
172
			}
173
		}
174
175
		throw new QRCodeException('Unable to determine type number.'); // @codeCoverageIgnore
176
	}
177
178
	/**
179
	 * @return mixed
180
	 */
181
	public function output(){
182
		$this->qrOutputInterface->setMatrix($this->getRawData());
183
		return $this->qrOutputInterface->dump();
184
	}
185
186
	/**
187
	 * @return array
188
	 */
189
	public function getRawData(){
190
		$minLostPoint = 0;
191
		$maskPattern = 0;
192
193
		foreach(range(0, 7) as $pattern){
194
			$this->getMatrix(true, $pattern);
195
			$lostPoint = 0;
196
			$darkCount = 0;
197
198
			$range1 = range(0, $this->pixelCount-1);
199
			$range2 = range(0, $this->pixelCount-2);
200
			$range3 = range(0, $this->pixelCount-7);
201
202
			// LEVEL1
203
			foreach($range1 as $row){
204
				foreach($range1 as $col){
205
					$sameCount = 0;
206
207
					foreach([-1, 0, 1] as $rr){
208
						if($row + $rr < 0 || $this->pixelCount <= $row + $rr){
209
							continue;
210
						}
211
212
						foreach([-1, 0, 1] as $cr){
213
214
							if(($rr === 0 && $cr === 0) || ($col + $cr < 0 || $this->pixelCount <= $col + $cr)){
215
								continue;
216
							}
217
218
							if($this->matrix[$row + $rr][$col + $cr] === $this->matrix[$row][$col]){
219
								$sameCount++;
220
							}
221
						}
222
					}
223
224
					if($sameCount > 5){
225
						$lostPoint += (3 + $sameCount - 5);
226
					}
227
				}
228
			}
229
230
			// LEVEL2
231
			foreach($range2 as $row){
232
				foreach($range2 as $col){
233
					$count = 0;
234
235
					if(
236
						   $this->matrix[$row    ][$col    ]
237
						|| $this->matrix[$row    ][$col + 1]
238
						|| $this->matrix[$row + 1][$col    ]
239
						|| $this->matrix[$row + 1][$col + 1]
240
					){
241
						$count++;
242
					}
243
244
					if($count === 0 || $count === 4){
245
						$lostPoint += 3;
246
					}
247
				}
248
			}
249
250
			// LEVEL3
251 View Code Duplication
			foreach($range1 as $row){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
252
				foreach($range3 as $col){
253
					if(
254
						    $this->matrix[$row][$col    ]
255
						&& !$this->matrix[$row][$col + 1]
256
						&&  $this->matrix[$row][$col + 2]
257
						&&  $this->matrix[$row][$col + 3]
258
						&&  $this->matrix[$row][$col + 4]
259
						&& !$this->matrix[$row][$col + 5]
260
						&&  $this->matrix[$row][$col + 6]
261
					){
262
						$lostPoint += 40;
263
					}
264
				}
265
			}
266
267 View Code Duplication
			foreach($range1 as $col){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
268
				foreach($range3 as $row){
269
					if(
270
						    $this->matrix[$row    ][$col]
271
						&& !$this->matrix[$row + 1][$col]
272
						&&  $this->matrix[$row + 2][$col]
273
						&&  $this->matrix[$row + 3][$col]
274
						&&  $this->matrix[$row + 4][$col]
275
						&& !$this->matrix[$row + 5][$col]
276
						&&  $this->matrix[$row + 6][$col]
277
					){
278
						$lostPoint += 40;
279
					}
280
				}
281
			}
282
283
			// LEVEL4
284
			foreach($range1 as $col){
285
				foreach($range1 as $row){
286
					if($this->matrix[$row][$col]){
287
						$darkCount++;
288
					}
289
				}
290
			}
291
292
			$lostPoint += (abs(100 * $darkCount / $this->pixelCount / $this->pixelCount - 50) / 5) * 10;
293
294
			if($pattern === 0 || $minLostPoint > $lostPoint){
295
				$minLostPoint = $lostPoint;
296
				$maskPattern = $pattern;
297
			}
298
299
		}
300
301
		$this->getMatrix(false, $maskPattern);
302
303
		return $this->matrix;
304
	}
305
306
	/**
307
	 * @param bool $test
308
	 */
309
	protected function setTypeNumber($test){
310
		$bits = Util::getBCHTypeNumber($this->typeNumber);
311
312
		foreach(range(0, 17) as $i){
313
			$a = (int)floor($i / 3);
314
			$b = $i % 3 + $this->pixelCount - 8 - 3;
315
316
			$this->matrix[$a][$b] = $this->matrix[$b][$a] = !$test && (($bits >> $i) & 1) === 1;
317
		}
318
319
	}
320
321
	/**
322
	 * @param bool $test
323
	 * @param int  $pattern
324
	 */
325
	protected function setTypeInfo($test, $pattern){
326
		$this->setPattern();
327
		$bits = Util::getBCHTypeInfo(($this->errorCorrectLevel << 3) | $pattern);
328
329
		foreach(range(0, 14) as $i){
330
			$mod = !$test && (($bits >> $i) & 1) === 1;
331
332
			switch(true){
333
				case $i < 6: $this->matrix[$i    ][8] = $mod; break;
334
				case $i < 8: $this->matrix[$i + 1][8] = $mod; break;
335
				default:
336
					$this->matrix[$this->pixelCount - 15 + $i][8] = $mod;
337
			}
338
339
			switch(true){
340 View Code Duplication
				case $i < 8: $this->matrix[8][$this->pixelCount - $i - 1] = $mod; break;
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
341 View Code Duplication
				case $i < 9: $this->matrix[8][           15 + 1 - $i - 1] = $mod; break;
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
342
				default:
343
					$this->matrix[8][15 - $i - 1] = $mod;
344
			}
345
346
		}
347
348
		$this->matrix[$this->pixelCount - 8][8] = !$test;
349
	}
350
351
	/**
352
	 * @throws \chillerlan\QRCode\QRCodeException
353
	 */
354
	protected function createData(){
355
		$this->bitBuffer->clear();
356
		$this->bitBuffer->put($this->qrDataInterface->mode, 4);
0 ignored issues
show
Bug introduced by
Accessing mode on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
357
		$this->bitBuffer->put(
358
			$this->qrDataInterface->mode === QRConst::MODE_KANJI
0 ignored issues
show
Bug introduced by
Accessing mode on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
359
				? floor($this->qrDataInterface->dataLength / 2)
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
360
				: $this->qrDataInterface->dataLength,
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
361
			$this->qrDataInterface->getLengthInBits($this->typeNumber)
362
		);
363
364
		$this->qrDataInterface->write($this->bitBuffer);
365
366
		$MAX_BITS = QRConst::MAX_BITS[$this->typeNumber][$this->errorCorrectLevel];
367
368
		if($this->bitBuffer->length > $MAX_BITS){
369
			throw new QRCodeException('code length overflow. ('.$this->bitBuffer->length.' > '.$MAX_BITS.'bit)');
370
		}
371
372
		// end code.
373
		if($this->bitBuffer->length + 4 <= $MAX_BITS){
374
			$this->bitBuffer->put(0, 4);
375
		}
376
377
		// padding
378
		while($this->bitBuffer->length % 8 !== 0){
379
			$this->bitBuffer->putBit(false);
380
		}
381
382
		// padding
383
		while(true){
384
385
			if($this->bitBuffer->length >= $MAX_BITS){
386
				break;
387
			}
388
389
			$this->bitBuffer->put(QRConst::PAD0, 8);
390
391
			if($this->bitBuffer->length >= $MAX_BITS){
392
				break;
393
			}
394
395
			$this->bitBuffer->put(QRConst::PAD1, 8);
396
		}
397
398
	}
399
400
	/**
401
	 * @return array
402
	 * @throws \chillerlan\QRCode\QRCodeException
403
	 */
404
	protected function createBytes(){
405
		$totalCodeCount = $maxDcCount = $maxEcCount = $offset = $index = 0;
406
		$rsBlocks = Util::getRSBlocks($this->typeNumber, $this->errorCorrectLevel);
407
		$rsBlockCount = count($rsBlocks);
408
		$dcdata = $ecdata = array_fill(0, $rsBlockCount, null);
409
410
		foreach($rsBlocks as $key => $value){
411
			$rsBlockTotal = $value[0];
412
			$rsBlockDataCount = $value[1];
413
414
			$maxDcCount = max($maxDcCount, $rsBlockDataCount);
415
			$maxEcCount = max($maxEcCount, $rsBlockTotal - $rsBlockDataCount);
416
417
			$dcdata[$key] = array_fill(0, $rsBlockDataCount, null);
418
419
			foreach($dcdata[$key] as $i => &$_dcdata){
420
				$bdata = $this->bitBuffer->buffer;
421
				$_dcdata = 0xff & $bdata[$i + $offset];
422
			}
423
424
			$offset += $rsBlockDataCount;
425
426
			$rsPoly = new Polynomial;
427
			$modPoly = new Polynomial;
428
429
			$i = 0;
430
			while($i < $rsBlockTotal - $rsBlockDataCount){
431
				$modPoly->setNum([1, $modPoly->gexp($i)]);
432
				$rsPoly->multiply($modPoly->num);
433
				$i++;
434
			}
435
436
			$rsPolyCount = count($rsPoly->num);
437
			$modPoly->setNum($dcdata[$key], $rsPolyCount - 1)->mod($rsPoly->num);
438
			$ecdata[$key] = array_fill(0, $rsPolyCount - 1, null);
439
			$add = count($modPoly->num) - count($ecdata[$key]);
440
441
			foreach($ecdata[$key] as $i => &$_ecdata){
442
				$modIndex = $i + $add;
443
				$_ecdata = $modIndex >= 0 ? $modPoly->num[$modIndex] : 0;
444
			}
445
446
			$totalCodeCount += $rsBlockTotal;
447
		}
448
449
		$data = array_fill(0, $totalCodeCount, null);
450
		$rsrange = range(0, $rsBlockCount - 1);
451
452
		$i = 0;
453 View Code Duplication
		while($i < $maxDcCount){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
454
			foreach($rsrange as $key){
455
				if($i < count($dcdata[$key])){
456
					$data[$index++] = $dcdata[$key][$i];
457
				}
458
			}
459
			$i++;
460
		}
461
462
		$i = 0;
463 View Code Duplication
		while($i < $maxEcCount){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
464
			foreach($rsrange as $key){
465
				if($i < count($ecdata[$key])){
466
					$data[$index++] = $ecdata[$key][$i];
467
				}
468
			}
469
			$i++;
470
		}
471
472
		return $data;
473
	}
474
475
	/**
476
	 * @param int $pattern
477
	 *
478
	 * @throws \chillerlan\QRCode\QRCodeException
479
	 */
480
	protected function mapData($pattern){
481
		$this->createData();
482
		$data = $this->createBytes();
483
		$inc = -1;
484
		$row = $this->pixelCount - 1;
485
		$bitIndex = 7;
486
		$byteIndex = 0;
487
		$dataCount = count($data);
488
489
		for($col = $this->pixelCount - 1; $col > 0; $col -= 2){
490
			if($col === 6){
491
				$col--;
492
			}
493
494
			while(true){
495
				$c = 0;
496
				while($c < 2){
497
					$_col = $col - $c;
498
499
					if($this->matrix[$row][$_col] === null){
500
						$dark = false;
501
502
						if($byteIndex < $dataCount){
503
							$dark = (($data[$byteIndex] >> $bitIndex) & 1) === 1;
504
						}
505
506
						$a = $row + $_col;
507
						$m = $row * $_col;
508
						$MASK_PATTERN = [
509
							QRConst::MASK_PATTERN000 => $a % 2,
510
							QRConst::MASK_PATTERN001 => $row % 2,
511
							QRConst::MASK_PATTERN010 => $_col % 3,
512
							QRConst::MASK_PATTERN011 => $a % 3,
513
							QRConst::MASK_PATTERN100 => (floor($row / 2) + floor($_col / 3)) % 2,
514
							QRConst::MASK_PATTERN101 => $m % 2 + $m % 3,
515
							QRConst::MASK_PATTERN110 => ($m % 2 + $m % 3) % 2,
516
							QRConst::MASK_PATTERN111 => ($m % 3 + $a % 2) % 2,
517
						][$pattern];
518
519
						if($MASK_PATTERN === 0){
520
							$dark = !$dark;
521
						}
522
523
						$this->matrix[$row][$_col] = $dark;
524
525
						$bitIndex--;
526
						if($bitIndex === -1){
527
							$byteIndex++;
528
							$bitIndex = 7;
529
						}
530
					}
531
					$c++;
532
				}
533
534
				$row += $inc;
535
				if($row < 0 || $this->pixelCount <= $row){
536
					$row -= $inc;
537
					$inc = -$inc;
538
					break;
539
				}
540
			}
541
		}
542
543
	}
544
545
	/**
546
	 * @throws \chillerlan\QRCode\QRCodeException
547
	 */
548
	protected function setPattern(){
549
		$range1 = range(-1, 7);
550
		$range2 = QRConst::PATTERN_POSITION[$this->typeNumber - 1];
551
		$range3 = range(8, $this->pixelCount - 8);
552
553
		// setupPositionProbePattern
554
		foreach([[0, 0], [$this->pixelCount - 7, 0], [0, $this->pixelCount - 7]] as $grid){
555
			$row = $grid[0];
556
			$col = $grid[1];
557
558
			$r = -1;
559
			while($r < 8){
560
				foreach($range1 as $c){
561
562
					if($row + $r <= -1 || $this->pixelCount <= $row + $r || $col + $c <= -1 || $this->pixelCount <= $col + $c){
563
						continue;
564
					}
565
566
					$this->matrix[$row + $r][$col + $c] =
567
						(0 <= $r && $r <= 6 && ($c === 0 || $c === 6))
568
						|| (0 <= $c && $c <= 6 && ($r === 0 || $r === 6))
569
						|| (2 <= $c && $c <= 4 && 2 <= $r && $r <= 4);
570
				}
571
				$r++;
572
			}
573
		}
574
575
		// setupPositionAdjustPattern
576
		foreach($range2 as $i => $posI){
577
			foreach($range2 as $j => $posJ){
578
				if($this->matrix[$posI][$posJ] !== null){
579
					continue;
580
				}
581
582
				$row = $col = -2;
583
				while($row < 2){
584
					while($col < 2){
585
						$this->matrix[$posI + $row][$posJ + $col] =
586
							   $row === -2 || $row === 2
587
							|| $col === -2 || $col === 2
588
							||($row ===  0 && $col === 0);
589
						$col++;
590
					}
591
					$row++;
592
				}
593
			}
594
		}
595
596
		// setupTimingPattern
597
		foreach($range3 as $i){
598
			if($this->matrix[$i][6] !== null){
599
				continue; // @codeCoverageIgnore
600
			}
601
602
			$this->matrix[$i][6] = $this->matrix[6][$i] = $i % 2 === 0;
603
		}
604
605
	}
606
607
	/**
608
	 * @param bool $test
609
	 * @param int  $maskPattern
610
	 *
611
	 * @throws \chillerlan\QRCode\QRCodeException
612
	 */
613
	protected function getMatrix($test, $maskPattern){
614
		$this->pixelCount = $this->typeNumber * 4 + 17;
615
		$this->matrix = array_fill(0, $this->pixelCount, array_fill(0, $this->pixelCount, null));
616
		$this->setTypeInfo($test, $maskPattern);
617
618
		if($this->typeNumber >= 7){
619
			$this->setTypeNumber($test);
620
		}
621
622
		$this->mapData($maskPattern);
623
	}
624
625
}
626