:octocat: mask pattern testing performance improvement

This commit is contained in:
smiley
2023-10-23 01:45:00 +02:00
parent af7ba49225
commit 3c2d23d8ac
2 changed files with 52 additions and 38 deletions
+49 -31
View File
@@ -14,7 +14,7 @@ namespace chillerlan\QRCode\Common;
use chillerlan\QRCode\Data\QRMatrix;
use chillerlan\QRCode\QRCodeException;
use Closure;
use function abs, array_search, count, intdiv, min;
use function abs, array_column, array_search, intdiv, min;
/**
* ISO/IEC 18004:2000 Section 8.8.1
@@ -55,6 +55,16 @@ final class MaskPattern{
self::PATTERN_111,
];
/*
* Penalty scores
*
* ISO/IEC 18004:2000 Section 8.8.1 - Table 24
*/
private const PENALTY_N1 = 3;
private const PENALTY_N2 = 3;
private const PENALTY_N3 = 40;
private const PENALTY_N4 = 10;
/**
* The current mask pattern value (0-7)
*/
@@ -114,6 +124,7 @@ final class MaskPattern{
*/
public static function getBestPattern(QRMatrix $QRMatrix):self{
$penalties = [];
$size = $QRMatrix->getSize();
foreach(self::PATTERNS as $pattern){
$mp = new self($pattern);
@@ -121,7 +132,7 @@ final class MaskPattern{
$penalty = 0;
for($level = 1; $level <= 4; $level++){
$penalty += self::{'testRule'.$level}($matrix, count($matrix), count($matrix[0]));
$penalty += self::{'testRule'.$level}($matrix, $size, $size);
}
$penalties[$pattern] = (int)$penalty;
@@ -135,42 +146,49 @@ final class MaskPattern{
* give penalty to them. Example: 00000 or 11111.
*/
public static function testRule1(array $matrix, int $height, int $width):int{
return (self::applyRule1($matrix, $height, $width, true) + self::applyRule1($matrix, $height, $width, false));
$penalty = 0;
// horizontal
foreach($matrix as $row){
$penalty += self::applyRule1($row);
}
// vertical
for($x = 0; $x < $width; $x++){
$penalty += self::applyRule1(array_column($matrix, $x));
}
return $penalty;
}
/**
*
*/
private static function applyRule1(array $matrix, int $height, int $width, bool $isHorizontal):int{
$penalty = 0;
$yLimit = ($isHorizontal) ? $height : $width;
$xLimit = ($isHorizontal) ? $width : $height;
private static function applyRule1(array $rc):int{
$penalty = 0;
$numSameBitCells = 0;
$prevBit = null;
for($y = 0; $y < $yLimit; $y++){
$numSameBitCells = 0;
$prevBit = null;
foreach($rc as $val){
for($x = 0; $x < $xLimit; $x++){
$bit = ($isHorizontal) ? $matrix[$y][$x] : $matrix[$x][$y];
if($bit === $prevBit){
$numSameBitCells++;
}
else{
if($numSameBitCells >= 5){
$penalty += (3 + ($numSameBitCells - 5));
}
$numSameBitCells = 1; // Include the cell itself.
$prevBit = $bit;
}
if($val === $prevBit){
$numSameBitCells++;
}
if($numSameBitCells >= 5){
$penalty += (3 + ($numSameBitCells - 5));
else{
if($numSameBitCells >= 5){
$penalty += (self::PENALTY_N1 + $numSameBitCells - 5);
}
$numSameBitCells = 1; // Include the cell itself.
$prevBit = $val;
}
}
if($numSameBitCells >= 5){
$penalty += (self::PENALTY_N1 + $numSameBitCells - 5);
}
return $penalty;
}
@@ -195,7 +213,7 @@ final class MaskPattern{
}
if(
$val === $row[($x + 1)]
$val === $row[($x + 1)]
&& $val === $matrix[($y + 1)][$x]
&& $val === $matrix[($y + 1)][($x + 1)]
){
@@ -204,7 +222,7 @@ final class MaskPattern{
}
}
return (3 * $penalty);
return (self::PENALTY_N2 * $penalty);
}
/**
@@ -255,7 +273,7 @@ final class MaskPattern{
}
}
return ($penalties * 40);
return ($penalties * self::PENALTY_N3);
}
/**
@@ -310,7 +328,7 @@ final class MaskPattern{
}
}
return (intdiv((abs($darkCells * 2 - $totalCells) * 10), $totalCells) * 10);
return (intdiv((abs($darkCells * 2 - $totalCells) * 10), $totalCells) * self::PENALTY_N4);
}
}
+3 -7
View File
@@ -181,14 +181,10 @@ class QRMatrix{
return $this->matrix;
}
$matrix = [];
$matrix = $this->matrix;
for($y = 0; $y < $this->moduleCount; $y++){
$matrix[$y] = [];
for($x = 0; $x < $this->moduleCount; $x++){
$matrix[$y][$x] = $this->checkType($x, $y, $this::IS_DARK);
}
foreach($matrix as &$row){
$row = array_map([$this, 'isDark'], $row);
}
return $matrix;