Completed
Push — master ( 693e1e...7ea7b3 )
by smiley
03:06
created

MaskPatternTester::testLevel4()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 0
dl 0
loc 13
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * Class MaskPatternTester
4
 *
5
 * @filesource   MaskPatternTester.php
6
 * @created      22.11.2017
7
 * @package      chillerlan\QRCode\Data
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\QRCode\Data;
14
15
/**
16
 * @link http://www.thonky.com/qr-code-tutorial/data-masking
17
 */
18
class MaskPatternTester{
19
20
	/**
21
	 * @var \chillerlan\QRCode\Data\QRMatrix
22
	 */
23
	protected $matrix;
24
25
	/**
26
	 * @var int
27
	 */
28
	protected $moduleCount;
29
30
	/**
31
	 * @param \chillerlan\QRCode\Data\QRMatrix $matrix
32
	 */
33
	public function setMatrix(QRMatrix $matrix){
34
		$this->matrix = $matrix;
35
		$this->moduleCount = $this->matrix->size();
36
	}
37
38
	/**
39
	 * Returns the penalty for the given mask pattern
40
	 *
41
	 * @see \chillerlan\QRCode\QRCode::getBestMaskPattern()
42
	 *
43
	 * @return float
44
	 */
45
	public function testPattern():float{
46
		$penalty  = 0;
47
48
		for($level = 1; $level <= 4; $level++){
49
			$penalty += call_user_func([$this, 'testLevel'.$level]);
50
		}
51
52
		return $penalty;
53
	}
54
55
	/**
56
	 * Checks for each group of five or more same-colored modules in a row (or column)
57
	 *
58
	 * @return float
59
	 */
60
	protected function testLevel1():float{
61
		$penalty = 0;
62
63
		foreach($this->matrix->matrix() as $y => $row){
64
			foreach($row as $x => $val){
65
				$count = 0;
66
67
				for($ry = -1; $ry <= 1; $ry++){
68
69
					if($y + $ry < 0 || $this->moduleCount <= $y + $ry){
70
						continue;
71
					}
72
73
					for($rx = -1; $rx <= 1; $rx++){
74
75
						if(($ry === 0 && $rx === 0) || ($x + $rx < 0 || $this->moduleCount <= $x + $rx)){
76
							continue;
77
						}
78
79
						if($this->matrix->check($x + $rx, $y + $ry) === ($val >> 8 > 0)){
80
							$count++;
81
						}
82
83
					}
84
				}
85
86
				if($count > 5){
87
					$penalty += (3 + $count - 5);
88
				}
89
90
			}
91
		}
92
93
		return $penalty;
94
	}
95
96
	/**
97
	 * Checks for each 2x2 area of same-colored modules in the matrix
98
	 *
99
	 * @return float
100
	 */
101
	protected function testLevel2():float{
102
		$penalty = 0;
103
104
		foreach($this->matrix->matrix() as $y => $row){
105
106
			if($y > $this->moduleCount - 2){
107
				break;
108
			}
109
110
			foreach($row as $x => $val){
111
112
				if($x > $this->moduleCount - 2){
113
					break;
114
				}
115
116
				$count = 0;
117
118
				if($val >> 8 > 0){
119
					$count++;
120
				}
121
122
				if($this->matrix->check($y, $x + 1)){
123
					$count++;
124
				}
125
126
				if($this->matrix->check($y + 1, $x)){
127
					$count++;
128
				}
129
130
				if($this->matrix->check($y + 1, $x + 1)){
131
					$count++;
132
				}
133
134
				if($count === 0 || $count === 4){
135
					$penalty += 3;
136
				}
137
138
			}
139
		}
140
141
		return $penalty;
142
	}
143
144
	/**
145
	 * Checks if there are patterns that look similar to the finder patterns
146
	 *
147
	 * @return float
148
	 */
149
	protected function testLevel3():float{
150
		$penalty = 0;
151
152
		foreach($this->matrix->matrix() as $y => $row){
153
			foreach($row as $x => $val){
154
155
				if($x > $this->moduleCount - 7){
156
					break;
157
				}
158
159
				if(
160
					$val >> 8 > 0
161
					&& !$this->matrix->check($x + 1, $y)
162
					&&  $this->matrix->check($x + 2, $y)
163
					&&  $this->matrix->check($x + 3, $y)
164
					&&  $this->matrix->check($x + 4, $y)
165
					&& !$this->matrix->check($x + 5, $y)
166
					&&  $this->matrix->check($x + 6, $y)
167
				){
168
					$penalty += 40;
169
				}
170
171
			}
172
		}
173
174
		for ($x = 0; $x < $this->moduleCount; $x++) {
175
			for ($y = 0; $y < $this->moduleCount - 6; $y++) {
176
177
				if(
178
					$this->matrix->check($x, $y    )
179
					&& !$this->matrix->check($x, $y + 1)
180
					&&  $this->matrix->check($x, $y + 2)
181
					&&  $this->matrix->check($x, $y + 3)
182
					&&  $this->matrix->check($x, $y + 4)
183
					&& !$this->matrix->check($x, $y + 5)
184
					&&  $this->matrix->check($x, $y + 6)
185
				){
186
					$penalty += 40;
187
				}
188
189
			}
190
		}
191
192
		return $penalty;
193
	}
194
195
	/**
196
	 * Checks if more than half of the modules are dark or light, with a larger penalty for a larger difference
197
	 *
198
	 * @return float
199
	 */
200
	protected function testLevel4():float {
201
		$count = 0;
202
203
		foreach($this->matrix->matrix() as $y => $row){
204
			foreach($row as $x => $val){
205
				if($val >> 8 > 0){
206
					$count++;
207
				}
208
			}
209
		}
210
211
		return (abs(100 * $count / $this->moduleCount / $this->moduleCount - 50) / 5) * 10;
212
	}
213
214
215
}
216