|
@@ -12,12 +12,12 @@
|
|
|
|
|
|
|
|
namespace chillerlan\QRCode\Data;
|
|
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\QRCode;
|
|
|
-use chillerlan\QRCode\Helpers\{BitBuffer, Polynomial};
|
|
|
|
|
|
|
+use chillerlan\QRCode\Helpers\BitBuffer;
|
|
|
use chillerlan\Settings\SettingsContainerInterface;
|
|
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
|
|
* Processes the binary data and maps it on a matrix which is then being returned
|
|
@@ -29,16 +29,6 @@ class QRData{
|
|
|
*/
|
|
*/
|
|
|
protected Version $version;
|
|
protected Version $version;
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * ECC temp data
|
|
|
|
|
- */
|
|
|
|
|
- protected array $ecdata;
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * ECC temp data
|
|
|
|
|
- */
|
|
|
|
|
- protected array $dcdata;
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* @var \chillerlan\QRCode\Data\QRDataModeInterface[]
|
|
* @var \chillerlan\QRCode\Data\QRDataModeInterface[]
|
|
|
*/
|
|
*/
|
|
@@ -109,9 +99,12 @@ class QRData{
|
|
|
* returns a fresh matrix object with the data written for the given $maskPattern
|
|
* returns a fresh matrix object with the data written for the given $maskPattern
|
|
|
*/
|
|
*/
|
|
|
public function initMatrix(int $maskPattern, bool $test = null):QRMatrix{
|
|
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))
|
|
return (new QRMatrix($this->version, $this->eccLevel))
|
|
|
->init($maskPattern, $test)
|
|
->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]),
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
}
|
|
}
|