Ejemplo n.º 1
0
 /**
  * Encodes "content" with the error correction level "ecLevel".
  *
  * @param  string               $content
  * @param  ErrorCorrectionLevel $ecLevel
  * @param  ?                    $hints
  * @return QrCode
  */
 public static function encode($content, ErrorCorrectionLevel $ecLevel, $encoding = self::DEFAULT_BYTE_MODE_ECODING)
 {
     // Pick an encoding mode appropriate for the content. Note that this
     // will not attempt to use multiple modes / segments even if that were
     // more efficient. Would be nice.
     $mode = self::chooseMode($content, $encoding);
     //debug($mode->get());
     // This will store the header information, like mode and length, as well
     // as "header" segments like an ECI segment.
     $headerBits = new BitArray();
     // Append ECI segment if applicable
     if ($mode->get() === Mode::BYTE && $encoding !== self::DEFAULT_BYTE_MODE_ECODING) {
         $eci = CharacterSetEci::getCharacterSetEciByName($encoding);
         if ($eci !== null) {
             self::appendEci($eci, $headerBits);
         }
     }
     // (With ECI in place,) Write the mode marker
     self::appendModeInfo($mode, $headerBits);
     // Collect data within the main segment, separately, to count its size
     // if needed. Don't add it to main payload yet.
     $dataBits = new BitArray();
     self::appendBytes($content, $mode, $dataBits, $encoding);
     // Hard part: need to know version to know how many bits length takes.
     // But need to know how many bits it takes to know version. First we
     // take a guess at version by assuming version will be the minimum, 1:
     $provisionalBitsNeeded = $headerBits->getSize() + $mode->getCharacterCountBits(Version::getVersionForNumber(1)) + $dataBits->getSize();
     $provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel);
     // Use that guess to calculate the right version. I am still not sure
     // this works in 100% of cases.
     $bitsNeeded = $headerBits->getSize() + $mode->getCharacterCountBits($provisionalVersion) + $dataBits->getSize();
     $version = self::chooseVersion($bitsNeeded, $ecLevel);
     $headerAndDataBits = new BitArray();
     $headerAndDataBits->appendBitArray($headerBits);
     // Find "length" of main segment and write it.
     $numLetters = $mode->get() === Mode::BYTE ? $dataBits->getSizeInBytes() : strlen($content);
     self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits);
     // Put data together into the overall payload.
     $headerAndDataBits->appendBitArray($dataBits);
     $ecBlocks = $version->getEcBlocksForLevel($ecLevel);
     $numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords();
     // Terminate the bits properly.
     self::terminateBits($numDataBytes, $headerAndDataBits);
     // Interleave data bits with error correction code.
     $finalBits = self::interleaveWithEcBytes($headerAndDataBits, $version->getTotalCodewords(), $numDataBytes, $ecBlocks->getNumBlocks());
     $qrCode = new QrCode();
     $qrCode->setErrorCorrectionLevel($ecLevel);
     $qrCode->setMode($mode);
     $qrCode->setVersion($version);
     // Choose the mask pattern and set to "qrCode".
     $dimension = $version->getDimensionForVersion();
     $matrix = new ByteMatrix($dimension, $dimension);
     $maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix);
     $qrCode->setMaskPattern($maskPattern);
     // Build the matrix and set it to "qrCode".
     MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix);
     $qrCode->setMatrix($matrix);
     return $qrCode;
 }
Ejemplo n.º 2
0
 /**
  * render(): defined by RendererInterface.
  *
  * @see    RendererInterface::render()
  * @param  QrCode $qrCode
  * @return string
  */
 public function render(QrCode $qrCode)
 {
     $input = $qrCode->getMatrix();
     $inputWidth = $input->getWidth();
     $inputHeight = $input->getHeight();
     $qrWidth = $inputWidth + ($this->getMargin() << 1);
     $qrHeight = $inputHeight + ($this->getMargin() << 1);
     $outputWidth = max($this->getWidth(), $qrWidth);
     $outputHeight = max($this->getHeight(), $qrHeight);
     $multiple = (int) min($outputWidth / $qrWidth, $outputHeight / $qrHeight);
     if ($this->shouldRoundDimensions()) {
         $outputWidth -= $outputWidth % $multiple;
         $outputHeight -= $outputHeight % $multiple;
     }
     // Padding includes both the quiet zone and the extra white pixels to
     // accommodate the requested dimensions. For example, if input is 25x25
     // the QR will be 33x33 including the quiet zone. If the requested size
     // is 200x160, the multiple will be 4, for a QR of 132x132. These will
     // handle all the padding from 100x100 (the actual QR) up to 200x160.
     $leftPadding = (int) (($outputWidth - $inputWidth * $multiple) / 2);
     $topPadding = (int) (($outputHeight - $inputHeight * $multiple) / 2);
     // Store calculated parameters
     $this->finalWidth = $outputWidth;
     $this->finalHeight = $outputHeight;
     $this->blockSize = $multiple;
     $this->init();
     $this->addColor('background', $this->getBackgroundColor());
     $this->addColor('foreground', $this->getForegroundColor());
     $this->drawBackground('background');
     foreach ($this->decorators as $decorator) {
         $decorator->preProcess($qrCode, $this, $outputWidth, $outputHeight, $leftPadding, $topPadding, $multiple);
     }
     for ($inputY = 0, $outputY = $topPadding; $inputY < $inputHeight; $inputY++, $outputY += $multiple) {
         for ($inputX = 0, $outputX = $leftPadding; $inputX < $inputWidth; $inputX++, $outputX += $multiple) {
             if ($input->get($inputX, $inputY) === 1) {
                 $this->drawBlock($outputX, $outputY, 'foreground');
             }
         }
     }
     foreach ($this->decorators as $decorator) {
         $decorator->postProcess($qrCode, $this, $outputWidth, $outputHeight, $leftPadding, $topPadding, $multiple);
     }
     return $this->getByteStream();
 }
Ejemplo n.º 3
0
 /**
  * postProcess(): defined by DecoratorInterface.
  *
  * @see    DecoratorInterface::postProcess()
  *
  * @param  QrCode            $qrCode
  * @param  RendererInterface $renderer
  * @param  integer           $outputWidth
  * @param  integer           $outputHeight
  * @param  integer           $leftPadding
  * @param  integer           $topPadding
  * @param  integer           $multiple
  * @return void
  */
 public function postProcess(QrCode $qrCode, RendererInterface $renderer, $outputWidth, $outputHeight, $leftPadding, $topPadding, $multiple)
 {
     $matrix = $qrCode->getMatrix();
     $positions = array(array(0, 0), array($matrix->getWidth() - 7, 0), array(0, $matrix->getHeight() - 7));
     $renderer->addColor('finder-outer', $this->getOuterColor());
     $renderer->addColor('finder-inner', $this->getInnerColor());
     foreach (self::$outerPositionDetectionPattern as $y => $row) {
         foreach ($row as $x => $isOuterSet) {
             $isInnerSet = self::$innerPositionDetectionPattern[$y][$x];
             if ($isOuterSet) {
                 foreach ($positions as $position) {
                     $renderer->drawBlock($leftPadding + $x * $multiple + $position[0] * $multiple, $topPadding + $y * $multiple + $position[1] * $multiple, 'finder-outer');
                 }
             }
             if ($isInnerSet) {
                 foreach ($positions as $position) {
                     $renderer->drawBlock($leftPadding + $x * $multiple + $position[0] * $multiple, $topPadding + $y * $multiple + $position[1] * $multiple, 'finder-inner');
                 }
             }
         }
     }
 }
Ejemplo n.º 4
0
 /**
  * render(): defined by RendererInterface.
  *
  * @see    RendererInterface::render()
  * @param  QrCode $qrCode
  * @return string
  */
 public function render(QrCode $qrCode)
 {
     $result = '';
     $matrix = $qrCode->getMatrix();
     $width = $matrix->getWidth();
     // Top margin
     for ($x = 0; $x < $this->margin; $x++) {
         $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin) . "\n";
     }
     // Body
     $array = $matrix->getArray();
     foreach ($array as $row) {
         $result .= str_repeat($this->emptyBlock, $this->margin);
         // left margin
         foreach ($row as $byte) {
             $result .= $byte ? $this->fullBlock : $this->emptyBlock;
         }
         $result .= str_repeat($this->emptyBlock, $this->margin);
         // right margin
         $result .= "\n";
     }
     // Bottom margin
     for ($x = 0; $x < $this->margin; $x++) {
         $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin) . "\n";
     }
     return $result;
 }