Example #1
1
 function addErrorCorrection()
 {
     // Now take the constructed codewords so far and add the
     // requried number of error correcting words at the end.
     // Depending on the symbol version and error corrction level
     // we normally have break up the whole data in blocks and add
     // error correction to each block. The required block structure
     // is specified in the standard. For small versions the whole data is
     // considered to be one block which makes it easy to start with.
     // Get block structur specification
     // (Total nbr blocks, (total words in block, data words in block, error words in block))
     $blks = $this->iQRCapacity->getBlockStructure($this->iVersion, $this->iErrLevel);
     // We can have all same block structure or we can have two different
     // block structures so we need to find ut which
     $ntype = count($blks);
     $this->iInfo = array();
     $blocks = array();
     $dataIdx = 0;
     $availableCodewords = count($this->iCodeWords);
     $this->iErrDebugInfostr = '';
     $blockoffset = 0;
     $blockinfo = array();
     $totalwords = 0;
     if ($ntype == 1 || $ntype == 2) {
         for ($k = 0; $k < $ntype; ++$k) {
             // -------------------------------------------------------------------------------
             // Handle each block structure
             // -------------------------------------------------------------------------------
             // 1. Fird find out how many block we need to use
             $nbrBlocks = $blks[$k][0];
             // 2. Find out total number of words (data+error correction) is in each block
             $nbrWordsInBlock = $blks[$k][1][0];
             // 3. Find out data words in each block
             $nbrDataInBlock = $blks[$k][1][1];
             // 4. Find out error correcting words in each block
             $nbrErrInBlock = $blks[$k][1][2];
             // Prepare RS coder
             $rs = new ReedSolomon($nbrErrInBlock, QREncoder::RSPrimitivePol);
             // Now split the data words in block and add the error correcting words to each block
             for ($i = 0; $i < $nbrBlocks; ++$i) {
                 // Extract the needed number of codewords for this block
                 for ($j = 0; $j < $nbrDataInBlock; ++$j) {
                     if ($dataIdx >= $availableCodewords) {
                         //throw new QRException('Trying to read past the last available codeword in block split', -1);
                         throw new QRExceptionL(1410);
                     }
                     $blocks[$i + $blockoffset][$j] = $this->iCodeWords[$dataIdx++];
                 }
                 // For easier split we save the structure of each block so we can easily find
                 // out info on each block we we loop throgh each block when we constructre the
                 // final codeword sequence
                 $blockinfo[$i + $blockoffset] = array($nbrWordsInBlock, $nbrDataInBlock, $nbrErrInBlock);
                 // Now append the requested number of error correcting codewords to the block
                 $rs->append($blocks[$i + $blockoffset]);
                 // Keep a sanity count on the total number of words (data+error correction)
                 $totalwords += count($blocks[$i + $blockoffset]);
                 $this->iErrDebugInfostr .= "\n=============\nSymbol block: Type={$k}, number=" . ($i + 1) . "/{$nbrBlocks} (Tot={$nbrWordsInBlock}, Data={$nbrDataInBlock}, Err={$nbrErrInBlock})\n=============\n";
                 $err = 0;
                 for ($j = 0; $j < $nbrWordsInBlock; ++$j) {
                     $fmt = '%08s (%02x)';
                     $this->iErrDebugInfostr .= sprintf($fmt, decbin($blocks[$i + $blockoffset][$j]), $blocks[$i + $blockoffset][$j]);
                     if ($j < $nbrWordsInBlock - 1) {
                         $this->iErrDebugInfostr .= ', ';
                     }
                     if ($j == $nbrDataInBlock - 1) {
                         $this->iErrDebugInfostr .= "\nError correction word in block:";
                     }
                     if ($j >= $nbrDataInBlock) {
                         ++$err;
                         if ($err % 4 == 0) {
                             $this->iErrDebugInfostr .= "\n";
                         }
                     } elseif (($j + 1) % 4 == 0 || $j == $nbrDataInBlock - 1) {
                         $this->iErrDebugInfostr .= "\n";
                     }
                 }
                 $this->iErrDebugInfostr .= "\n";
             }
             $blockoffset += $nbrBlocks;
         }
     } else {
         //throw new QRException('Internal error: Expected 1 or 2 as the number of block structures.');
         throw new QRExceptionL(1411);
     }
     // Now when we have all block we need to create the final message codeword sequence which we do by
     // taking data and error correction codewords from each block in turn: data block
     // 1, codeword 1; data block 2, codeword 1; data block 3, codeword 1; and similarly to data block n - 1, final
     // codeword; data block n, final codeword; then error correction block 1, codeword 1, error correction block 2,
     // codeword 1, ... and similarly to error correction block n - 1, final codeword; error correction block n, final codeword.
     // QR Code symbols contain data and error correction blocks which always exactly fill the symbol codeword capacity.
     // In certain versions, however, there may be a need for 3, 4 or 7 Remainder Bits to be appended to the final
     // message bit stream in order exactly to fill the number of modules in the encoding region.
     $totalNbrOfBlocks = $blockoffset;
     // Collect all data words
     $this->iFinalCodewordSequence = array();
     $idx = 0;
     $cwidx = 0;
     while ($idx < $availableCodewords) {
         for ($i = 0; $i < $totalNbrOfBlocks; ++$i) {
             if ($cwidx < $blockinfo[$i][1]) {
                 $this->iFinalCodewordSequence[$idx++] = $blocks[$i][$cwidx];
             }
         }
         ++$cwidx;
     }
     // Collect all error correction words
     $erridx = 0;
     while ($erridx < $nbrErrInBlock) {
         for ($i = 0; $i < $totalNbrOfBlocks; ++$i) {
             $this->iFinalCodewordSequence[$idx++] = $blocks[$i][$blockinfo[$i][1] + $erridx];
         }
         ++$erridx;
     }
     $n = count($this->iFinalCodewordSequence);
     // Do a sanity check that we have the correct total number of data+error codewords
     if ($totalwords != $n) {
         throw new QRExeption('Internal error: Number of total codewords does not match after split!!');
     }
     // Create the final bitsequence to be put in the symbol matrix
     $this->iFinalBitArray = array();
     Utils::ByteArray2Bits($this->iFinalCodewordSequence, $this->iFinalBitArray);
     $this->iErrDebugInfostr .= "\n=========== INTERLEAVED CODE SEQUENCE (Total={$n} =============\n";
     for ($i = 0; $i < $n; ++$i) {
         // $fmt = '%08s (%02x)';
         $v = $this->iFinalCodewordSequence[$i];
         $this->iErrDebugInfostr .= sprintf($fmt, decbin($v), $v);
         if ($i < $n - 1) {
             $this->iErrDebugInfostr .= ', ';
         }
         if (($i + 1) % 4 == 0) {
             $this->iErrDebugInfostr .= "\n";
         }
     }
     $this->iErrDebugInfostr .= "\n";
 }
 function rs(&$binary, $bytes, $datablock, $rsblock)
 {
     $blocks = floor(($bytes + 2) / $datablock);
     $rs = new ReedSolomon($rsblock);
     for ($b = 0; $b < $blocks; $b++) {
         $buf = array();
         $p = 0;
         for ($n = $b; $n < $bytes; $n += $blocks) {
             array_push($buf, $binary[$n]);
         }
         $enc = $rs->encodeArray($buf);
         // comes back reversed
         $p = $rsblock - 1;
         for ($n = $b; $n < $rsblock * $blocks; $n += $blocks) {
             $binary[$bytes + $n] = $enc[$p--];
         }
     }
 }