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