14
14
use chillerlan \QRCode \Data \QRMatrix ;
15
15
use chillerlan \QRCode \QRCodeException ;
16
16
use Closure ;
17
- use function abs , array_search , count , intdiv , min ;
17
+ use function abs , array_column , array_search , intdiv , min ;
18
18
19
19
/**
20
20
* ISO/IEC 18004:2000 Section 8.8.1
@@ -55,6 +55,16 @@ final class MaskPattern{
55
55
self ::PATTERN_111 ,
56
56
];
57
57
58
+ /*
59
+ * Penalty scores
60
+ *
61
+ * ISO/IEC 18004:2000 Section 8.8.1 - Table 24
62
+ */
63
+ private const PENALTY_N1 = 3 ;
64
+ private const PENALTY_N2 = 3 ;
65
+ private const PENALTY_N3 = 40 ;
66
+ private const PENALTY_N4 = 10 ;
67
+
58
68
/**
59
69
* The current mask pattern value (0-7)
60
70
*/
@@ -114,14 +124,15 @@ public function getMask():Closure{
114
124
*/
115
125
public static function getBestPattern (QRMatrix $ QRMatrix ):self {
116
126
$ penalties = [];
127
+ $ size = $ QRMatrix ->getSize ();
117
128
118
129
foreach (self ::PATTERNS as $ pattern ){
119
130
$ mp = new self ($ pattern );
120
131
$ matrix = (clone $ QRMatrix )->setFormatInfo ($ mp )->mask ($ mp )->getMatrix (true );
121
132
$ penalty = 0 ;
122
133
123
134
for ($ level = 1 ; $ level <= 4 ; $ level ++){
124
- $ penalty += self ::{'testRule ' .$ level }($ matrix , count ( $ matrix ), count ( $ matrix [ 0 ]) );
135
+ $ penalty += self ::{'testRule ' .$ level }($ matrix , $ size , $ size );
125
136
}
126
137
127
138
$ penalties [$ pattern ] = (int )$ penalty ;
@@ -135,42 +146,49 @@ public static function getBestPattern(QRMatrix $QRMatrix):self{
135
146
* give penalty to them. Example: 00000 or 11111.
136
147
*/
137
148
public static function testRule1 (array $ matrix , int $ height , int $ width ):int {
138
- return (self ::applyRule1 ($ matrix , $ height , $ width , true ) + self ::applyRule1 ($ matrix , $ height , $ width , false ));
149
+ $ penalty = 0 ;
150
+
151
+ // horizontal
152
+ foreach ($ matrix as $ row ){
153
+ $ penalty += self ::applyRule1 ($ row );
154
+ }
155
+
156
+ // vertical
157
+ for ($ x = 0 ; $ x < $ width ; $ x ++){
158
+ $ penalty += self ::applyRule1 (array_column ($ matrix , $ x ));
159
+ }
160
+
161
+ return $ penalty ;
139
162
}
140
163
141
164
/**
142
165
*
143
166
*/
144
- private static function applyRule1 (array $ matrix , int $ height , int $ width , bool $ isHorizontal ):int {
145
- $ penalty = 0 ;
146
- $ yLimit = ( $ isHorizontal ) ? $ height : $ width ;
147
- $ xLimit = ( $ isHorizontal ) ? $ width : $ height ;
167
+ private static function applyRule1 (array $ rc ):int {
168
+ $ penalty = 0 ;
169
+ $ numSameBitCells = 0 ;
170
+ $ prevBit = null ;
148
171
149
- for ($ y = 0 ; $ y < $ yLimit ; $ y ++){
150
- $ numSameBitCells = 0 ;
151
- $ prevBit = null ;
172
+ foreach ($ rc as $ val ){
152
173
153
- for ($ x = 0 ; $ x < $ xLimit ; $ x ++){
154
- $ bit = ($ isHorizontal ) ? $ matrix [$ y ][$ x ] : $ matrix [$ x ][$ y ];
174
+ if ($ val === $ prevBit ){
175
+ $ numSameBitCells ++;
176
+ }
177
+ else {
155
178
156
- if ($ bit === $ prevBit ){
157
- $ numSameBitCells ++ ;
179
+ if ($ numSameBitCells >= 5 ){
180
+ $ penalty += ( self :: PENALTY_N1 + $ numSameBitCells - 5 ) ;
158
181
}
159
- else {
160
-
161
- if ($ numSameBitCells >= 5 ){
162
- $ penalty += (3 + ($ numSameBitCells - 5 ));
163
- }
164
182
165
- $ numSameBitCells = 1 ; // Include the cell itself.
166
- $ prevBit = $ bit ;
167
- }
168
- }
169
- if ($ numSameBitCells >= 5 ){
170
- $ penalty += (3 + ($ numSameBitCells - 5 ));
183
+ $ numSameBitCells = 1 ; // Include the cell itself.
184
+ $ prevBit = $ val ;
171
185
}
172
186
}
173
187
188
+ if ($ numSameBitCells >= 5 ){
189
+ $ penalty += (self ::PENALTY_N1 + $ numSameBitCells - 5 );
190
+ }
191
+
174
192
return $ penalty ;
175
193
}
176
194
@@ -195,7 +213,7 @@ public static function testRule2(array $matrix, int $height, int $width):int{
195
213
}
196
214
197
215
if (
198
- $ val === $ row [($ x + 1 )]
216
+ $ val === $ row [($ x + 1 )]
199
217
&& $ val === $ matrix [($ y + 1 )][$ x ]
200
218
&& $ val === $ matrix [($ y + 1 )][($ x + 1 )]
201
219
){
@@ -204,7 +222,7 @@ public static function testRule2(array $matrix, int $height, int $width):int{
204
222
}
205
223
}
206
224
207
- return (3 * $ penalty );
225
+ return (self :: PENALTY_N2 * $ penalty );
208
226
}
209
227
210
228
/**
@@ -255,7 +273,7 @@ public static function testRule3(array $matrix, int $height, int $width):int{
255
273
}
256
274
}
257
275
258
- return ($ penalties * 40 );
276
+ return ($ penalties * self :: PENALTY_N3 );
259
277
}
260
278
261
279
/**
@@ -310,7 +328,7 @@ public static function testRule4(array $matrix, int $height, int $width):int{
310
328
}
311
329
}
312
330
313
- return (intdiv ((abs ($ darkCells * 2 - $ totalCells ) * 10 ), $ totalCells ) * 10 );
331
+ return (intdiv ((abs ($ darkCells * 2 - $ totalCells ) * 10 ), $ totalCells ) * self :: PENALTY_N4 );
314
332
}
315
333
316
334
}
0 commit comments