Skip to content

Commit 3c2d23d

Browse files
committed
:octocat: mask pattern testing performance improvement
1 parent af7ba49 commit 3c2d23d

File tree

2 files changed

+50
-36
lines changed

2 files changed

+50
-36
lines changed

src/Common/MaskPattern.php

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use chillerlan\QRCode\Data\QRMatrix;
1515
use chillerlan\QRCode\QRCodeException;
1616
use Closure;
17-
use function abs, array_search, count, intdiv, min;
17+
use function abs, array_column, array_search, intdiv, min;
1818

1919
/**
2020
* ISO/IEC 18004:2000 Section 8.8.1
@@ -55,6 +55,16 @@ final class MaskPattern{
5555
self::PATTERN_111,
5656
];
5757

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+
5868
/**
5969
* The current mask pattern value (0-7)
6070
*/
@@ -114,14 +124,15 @@ public function getMask():Closure{
114124
*/
115125
public static function getBestPattern(QRMatrix $QRMatrix):self{
116126
$penalties = [];
127+
$size = $QRMatrix->getSize();
117128

118129
foreach(self::PATTERNS as $pattern){
119130
$mp = new self($pattern);
120131
$matrix = (clone $QRMatrix)->setFormatInfo($mp)->mask($mp)->getMatrix(true);
121132
$penalty = 0;
122133

123134
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);
125136
}
126137

127138
$penalties[$pattern] = (int)$penalty;
@@ -135,42 +146,49 @@ public static function getBestPattern(QRMatrix $QRMatrix):self{
135146
* give penalty to them. Example: 00000 or 11111.
136147
*/
137148
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;
139162
}
140163

141164
/**
142165
*
143166
*/
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;
148171

149-
for($y = 0; $y < $yLimit; $y++){
150-
$numSameBitCells = 0;
151-
$prevBit = null;
172+
foreach($rc as $val){
152173

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{
155178

156-
if($bit === $prevBit){
157-
$numSameBitCells++;
179+
if($numSameBitCells >= 5){
180+
$penalty += (self::PENALTY_N1 + $numSameBitCells - 5);
158181
}
159-
else{
160-
161-
if($numSameBitCells >= 5){
162-
$penalty += (3 + ($numSameBitCells - 5));
163-
}
164182

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;
171185
}
172186
}
173187

188+
if($numSameBitCells >= 5){
189+
$penalty += (self::PENALTY_N1 + $numSameBitCells - 5);
190+
}
191+
174192
return $penalty;
175193
}
176194

@@ -195,7 +213,7 @@ public static function testRule2(array $matrix, int $height, int $width):int{
195213
}
196214

197215
if(
198-
$val === $row[($x + 1)]
216+
$val === $row[($x + 1)]
199217
&& $val === $matrix[($y + 1)][$x]
200218
&& $val === $matrix[($y + 1)][($x + 1)]
201219
){
@@ -204,7 +222,7 @@ public static function testRule2(array $matrix, int $height, int $width):int{
204222
}
205223
}
206224

207-
return (3 * $penalty);
225+
return (self::PENALTY_N2 * $penalty);
208226
}
209227

210228
/**
@@ -255,7 +273,7 @@ public static function testRule3(array $matrix, int $height, int $width):int{
255273
}
256274
}
257275

258-
return ($penalties * 40);
276+
return ($penalties * self::PENALTY_N3);
259277
}
260278

261279
/**
@@ -310,7 +328,7 @@ public static function testRule4(array $matrix, int $height, int $width):int{
310328
}
311329
}
312330

313-
return (intdiv((abs($darkCells * 2 - $totalCells) * 10), $totalCells) * 10);
331+
return (intdiv((abs($darkCells * 2 - $totalCells) * 10), $totalCells) * self::PENALTY_N4);
314332
}
315333

316334
}

src/Data/QRMatrix.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,10 @@ public function getMatrix(bool $boolean = null):array{
181181
return $this->matrix;
182182
}
183183

184-
$matrix = [];
184+
$matrix = $this->matrix;
185185

186-
for($y = 0; $y < $this->moduleCount; $y++){
187-
$matrix[$y] = [];
188-
189-
for($x = 0; $x < $this->moduleCount; $x++){
190-
$matrix[$y][$x] = $this->checkType($x, $y, $this::IS_DARK);
191-
}
186+
foreach($matrix as &$row){
187+
$row = array_map([$this, 'isDark'], $row);
192188
}
193189

194190
return $matrix;

0 commit comments

Comments
 (0)