:octocat: extract ECC/RS operations

This commit is contained in:
codemasher
2021-01-09 20:41:51 +01:00
parent 36cb9d6bc1
commit 26536de7f0
4 changed files with 144 additions and 118 deletions
+7 -111
View File
@@ -12,12 +12,12 @@
namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\Common\{EccLevel, Mode, Version};
use chillerlan\QRCode\Common\{EccLevel, Mode, ReedSolomon, Version};
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Helpers\{BitBuffer, Polynomial};
use chillerlan\QRCode\Helpers\BitBuffer;
use chillerlan\Settings\SettingsContainerInterface;
use function array_fill, array_merge, count, max, range, sprintf;
use function range, sprintf;
/**
* Processes the binary data and maps it on a matrix which is then being returned
@@ -29,16 +29,6 @@ class QRData{
*/
protected Version $version;
/**
* ECC temp data
*/
protected array $ecdata;
/**
* ECC temp data
*/
protected array $dcdata;
/**
* @var \chillerlan\QRCode\Data\QRDataModeInterface[]
*/
@@ -109,9 +99,12 @@ class QRData{
* returns a fresh matrix object with the data written for the given $maskPattern
*/
public function initMatrix(int $maskPattern, bool $test = null):QRMatrix{
$rs = new ReedSolomon($this->version, $this->eccLevel);
$data = $rs->interleaveEcBytes($this->bitBuffer);
return (new QRMatrix($this->version, $this->eccLevel))
->init($maskPattern, $test)
->mapData($this->maskECC(), $maskPattern)
->mapData($data, $maskPattern)
;
}
@@ -223,101 +216,4 @@ class QRData{
}
/**
* ECC masking
*
* ISO/IEC 18004:2000 Section 8.5 ff
*
* @see http://www.thonky.com/qr-code-tutorial/error-correction-coding
*/
protected function maskECC():array{
[$l1, $l2, $b1, $b2] = $this->eccLevel->getRSBlocks($this->version->getVersionNumber());
$rsBlocks = array_fill(0, $l1, [$b1, $b2]);
$rsCount = $l1 + $l2;
$this->ecdata = array_fill(0, $rsCount, []);
$this->dcdata = $this->ecdata;
if($l2 > 0){
$rsBlocks = array_merge($rsBlocks, array_fill(0, $l2, [$b1 + 1, $b2 + 1]));
}
$totalCodeCount = 0;
$maxDcCount = 0;
$maxEcCount = 0;
$offset = 0;
$bitBuffer = $this->bitBuffer->getBuffer();
foreach($rsBlocks as $key => $block){
[$rsBlockTotal, $dcCount] = $block;
$ecCount = $rsBlockTotal - $dcCount;
$maxDcCount = max($maxDcCount, $dcCount);
$maxEcCount = max($maxEcCount, $ecCount);
$this->dcdata[$key] = array_fill(0, $dcCount, null);
foreach($this->dcdata[$key] as $a => $_z){
$this->dcdata[$key][$a] = 0xff & $bitBuffer[$a + $offset];
}
[$num, $add] = $this->poly($key, $ecCount);
foreach($this->ecdata[$key] as $c => $_){
$modIndex = $c + $add;
$this->ecdata[$key][$c] = $modIndex >= 0 ? $num[$modIndex] : 0;
}
$offset += $dcCount;
$totalCodeCount += $rsBlockTotal;
}
$data = array_fill(0, $totalCodeCount, null);
$index = 0;
$mask = function(array $arr, int $count) use (&$data, &$index, $rsCount):void{
for($x = 0; $x < $count; $x++){
for($y = 0; $y < $rsCount; $y++){
if($x < count($arr[$y])){
$data[$index] = $arr[$y][$x];
$index++;
}
}
}
};
$mask($this->dcdata, $maxDcCount);
$mask($this->ecdata, $maxEcCount);
return $data;
}
/**
* helper method for the polynomial operations
*/
protected function poly(int $key, int $count):array{
$rsPoly = new Polynomial;
$modPoly = new Polynomial;
for($i = 0; $i < $count; $i++){
$modPoly->setNum([1, $modPoly->gexp($i)]);
$rsPoly->multiply($modPoly->getNum());
}
$rsPolyCount = count($rsPoly->getNum());
$modPoly
->setNum($this->dcdata[$key], $rsPolyCount - 1)
->mod($rsPoly->getNum())
;
$this->ecdata[$key] = array_fill(0, $rsPolyCount - 1, null);
$num = $modPoly->getNum();
return [
$num,
count($num) - count($this->ecdata[$key]),
];
}
}