:octocat: move deinterleaving to ReedSolomonDecoder

This commit is contained in:
smiley
2023-01-31 19:02:24 +01:00
parent 118d9ed591
commit 8eb54d4eef
2 changed files with 94 additions and 85 deletions
+5 -81
View File
@@ -78,96 +78,20 @@ final class Decoder{
throw new QRCodeDecoderException('unable to read version or format info'); // @codeCoverageIgnore
}
$resultBytes = (new ReedSolomonDecoder)->decode($this->getDataBlocks($rawCodewords));
// Decode the contents of that stream of bytes
$resultBytes = (new ReedSolomonDecoder($this->version, $this->eccLevel))->decode($rawCodewords);
return $this->decodeBitStream($resultBytes);
}
/**
* When QR Codes use multiple data blocks, they are actually interleaved.
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
* method will separate the data into original blocks.
* Decode the contents of that stream of bytes
*
* @param array $rawCodewords bytes as read directly from the QR Code
*
* @return array DataBlocks containing original bytes, "de-interleaved" from representation in the QR Code
* @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
*/
private function getDataBlocks(array $rawCodewords):array{
// Figure out the number and size of data blocks used by this version and
// error correction level
/** @phan-suppress-next-line PhanTypeMismatchArgumentNullable */
[$numEccCodewords, $eccBlocks] = $this->version->getRSBlocks($this->eccLevel);
// Now establish DataBlocks of the appropriate size and number of data codewords
$result = [];//new DataBlock[$totalBlocks];
$numResultBlocks = 0;
foreach($eccBlocks as $blockData){
[$numEccBlocks, $eccPerBlock] = $blockData;
for($i = 0; $i < $numEccBlocks; $i++, $numResultBlocks++){
$result[$numResultBlocks] = [$eccPerBlock, array_fill(0, $numEccCodewords + $eccPerBlock, 0)];
}
}
// All blocks have the same amount of data, except that the last n
// (where n may be 0) have 1 more byte. Figure out where these start.
/** @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset */
$shorterBlocksTotalCodewords = count($result[0][1]);
$longerBlocksStartAt = count($result) - 1;
while($longerBlocksStartAt >= 0){
$numCodewords = count($result[$longerBlocksStartAt][1]);
if($numCodewords == $shorterBlocksTotalCodewords){
break;
}
$longerBlocksStartAt--;
}
$longerBlocksStartAt++;
$shorterBlocksNumDataCodewords = $shorterBlocksTotalCodewords - $numEccCodewords;
// The last elements of result may be 1 element longer;
// first fill out as many elements as all of them have
$rawCodewordsOffset = 0;
for($i = 0; $i < $shorterBlocksNumDataCodewords; $i++){
for($j = 0; $j < $numResultBlocks; $j++){
$result[$j][1][$i] = $rawCodewords[$rawCodewordsOffset++];
}
}
// Fill out the last data block in the longer ones
for($j = $longerBlocksStartAt; $j < $numResultBlocks; $j++){
$result[$j][1][$shorterBlocksNumDataCodewords] = $rawCodewords[$rawCodewordsOffset++];
}
// Now add in error correction blocks
/** @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset */
$max = count($result[0][1]);
for($i = $shorterBlocksNumDataCodewords; $i < $max; $i++){
for($j = 0; $j < $numResultBlocks; $j++){
$iOffset = $j < $longerBlocksStartAt ? $i : $i + 1;
$result[$j][1][$iOffset] = $rawCodewords[$rawCodewordsOffset++];
}
}
return $result;
}
/**
* @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
*/
private function decodeBitStream(array $bytes):DecoderResult{
$bitBuffer = new BitBuffer($bytes);
private function decodeBitStream(BitBuffer $bitBuffer):DecoderResult{
$versionNumber = $this->version->getVersionNumber();
$symbolSequence = -1;
$parityData = -1;
$versionNumber = $this->version->getVersionNumber();
$eciCharset = null;
$fc1InEffect = false;
$result = '';