vendor/endroid/qr-code/src/Writer/AbstractGdWriter.php line 30

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Endroid\QrCode\Writer;
  4. use Endroid\QrCode\Bacon\MatrixFactory;
  5. use Endroid\QrCode\Exception\ValidationException;
  6. use Endroid\QrCode\ImageData\LabelImageData;
  7. use Endroid\QrCode\ImageData\LogoImageData;
  8. use Endroid\QrCode\Label\LabelAlignment;
  9. use Endroid\QrCode\Label\LabelInterface;
  10. use Endroid\QrCode\Logo\LogoInterface;
  11. use Endroid\QrCode\Matrix\MatrixInterface;
  12. use Endroid\QrCode\QrCodeInterface;
  13. use Endroid\QrCode\RoundBlockSizeMode;
  14. use Endroid\QrCode\Writer\Result\GdResult;
  15. use Endroid\QrCode\Writer\Result\ResultInterface;
  16. use Zxing\QrReader;
  17. abstract class AbstractGdWriter implements WriterInterfaceValidatingWriterInterface
  18. {
  19.     protected function getMatrix(QrCodeInterface $qrCode): MatrixInterface
  20.     {
  21.         $matrixFactory = new MatrixFactory();
  22.         return $matrixFactory->create($qrCode);
  23.     }
  24.     public function write(QrCodeInterface $qrCodeLogoInterface $logo nullLabelInterface $label null, array $options = []): ResultInterface
  25.     {
  26.         if (!extension_loaded('gd')) {
  27.             throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
  28.         }
  29.         $matrix $this->getMatrix($qrCode);
  30.         $baseBlockSize RoundBlockSizeMode::None === $qrCode->getRoundBlockSizeMode() ? 10 intval($matrix->getBlockSize());
  31.         $baseImage imagecreatetruecolor($matrix->getBlockCount() * $baseBlockSize$matrix->getBlockCount() * $baseBlockSize);
  32.         if (!$baseImage) {
  33.             throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
  34.         }
  35.         /** @var int $foregroundColor */
  36.         $foregroundColor imagecolorallocatealpha(
  37.             $baseImage,
  38.             $qrCode->getForegroundColor()->getRed(),
  39.             $qrCode->getForegroundColor()->getGreen(),
  40.             $qrCode->getForegroundColor()->getBlue(),
  41.             $qrCode->getForegroundColor()->getAlpha()
  42.         );
  43.         /** @var int $transparentColor */
  44.         $transparentColor imagecolorallocatealpha($baseImage255255255127);
  45.         imagefill($baseImage00$transparentColor);
  46.         for ($rowIndex 0$rowIndex $matrix->getBlockCount(); ++$rowIndex) {
  47.             for ($columnIndex 0$columnIndex $matrix->getBlockCount(); ++$columnIndex) {
  48.                 if (=== $matrix->getBlockValue($rowIndex$columnIndex)) {
  49.                     imagefilledrectangle(
  50.                         $baseImage,
  51.                         $columnIndex $baseBlockSize,
  52.                         $rowIndex $baseBlockSize,
  53.                         ($columnIndex 1) * $baseBlockSize 1,
  54.                         ($rowIndex 1) * $baseBlockSize 1,
  55.                         $foregroundColor
  56.                     );
  57.                 }
  58.             }
  59.         }
  60.         $targetWidth $matrix->getOuterSize();
  61.         $targetHeight $matrix->getOuterSize();
  62.         if ($label instanceof LabelInterface) {
  63.             $labelImageData LabelImageData::createForLabel($label);
  64.             $targetHeight += $labelImageData->getHeight() + $label->getMargin()->getTop() + $label->getMargin()->getBottom();
  65.         }
  66.         $targetImage imagecreatetruecolor($targetWidth$targetHeight);
  67.         if (!$targetImage) {
  68.             throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
  69.         }
  70.         /** @var int $backgroundColor */
  71.         $backgroundColor imagecolorallocatealpha(
  72.             $targetImage,
  73.             $qrCode->getBackgroundColor()->getRed(),
  74.             $qrCode->getBackgroundColor()->getGreen(),
  75.             $qrCode->getBackgroundColor()->getBlue(),
  76.             $qrCode->getBackgroundColor()->getAlpha()
  77.         );
  78.         imagefill($targetImage00$backgroundColor);
  79.         imagecopyresampled(
  80.             $targetImage,
  81.             $baseImage,
  82.             $matrix->getMarginLeft(),
  83.             $matrix->getMarginLeft(),
  84.             0,
  85.             0,
  86.             $matrix->getInnerSize(),
  87.             $matrix->getInnerSize(),
  88.             imagesx($baseImage),
  89.             imagesy($baseImage)
  90.         );
  91.         if ($qrCode->getBackgroundColor()->getAlpha() > 0) {
  92.             imagesavealpha($targetImagetrue);
  93.         }
  94.         $result = new GdResult($matrix$targetImage);
  95.         if ($logo instanceof LogoInterface) {
  96.             $result $this->addLogo($logo$result);
  97.         }
  98.         if ($label instanceof LabelInterface) {
  99.             $result $this->addLabel($label$result);
  100.         }
  101.         return $result;
  102.     }
  103.     private function addLogo(LogoInterface $logoGdResult $result): GdResult
  104.     {
  105.         $logoImageData LogoImageData::createForLogo($logo);
  106.         if ('image/svg+xml' === $logoImageData->getMimeType()) {
  107.             throw new \Exception('PNG Writer does not support SVG logo');
  108.         }
  109.         $targetImage $result->getImage();
  110.         $matrix $result->getMatrix();
  111.         if ($logoImageData->getPunchoutBackground()) {
  112.             /** @var int $transparent */
  113.             $transparent imagecolorallocatealpha($targetImage255255255127);
  114.             imagealphablending($targetImagefalse);
  115.             $xOffsetStart intval($matrix->getOuterSize() / $logoImageData->getWidth() / 2);
  116.             $yOffsetStart intval($matrix->getOuterSize() / $logoImageData->getHeight() / 2);
  117.             for ($xOffset $xOffsetStart$xOffset $xOffsetStart $logoImageData->getWidth(); ++$xOffset) {
  118.                 for ($yOffset $yOffsetStart$yOffset $yOffsetStart $logoImageData->getHeight(); ++$yOffset) {
  119.                     imagesetpixel($targetImage$xOffset$yOffset$transparent);
  120.                 }
  121.             }
  122.         }
  123.         imagecopyresampled(
  124.             $targetImage,
  125.             $logoImageData->getImage(),
  126.             intval($matrix->getOuterSize() / $logoImageData->getWidth() / 2),
  127.             intval($matrix->getOuterSize() / $logoImageData->getHeight() / 2),
  128.             0,
  129.             0,
  130.             $logoImageData->getWidth(),
  131.             $logoImageData->getHeight(),
  132.             imagesx($logoImageData->getImage()),
  133.             imagesy($logoImageData->getImage())
  134.         );
  135.         return new GdResult($matrix$targetImage);
  136.     }
  137.     private function addLabel(LabelInterface $labelGdResult $result): GdResult
  138.     {
  139.         $targetImage $result->getImage();
  140.         $labelImageData LabelImageData::createForLabel($label);
  141.         /** @var int $textColor */
  142.         $textColor imagecolorallocatealpha(
  143.             $targetImage,
  144.             $label->getTextColor()->getRed(),
  145.             $label->getTextColor()->getGreen(),
  146.             $label->getTextColor()->getBlue(),
  147.             $label->getTextColor()->getAlpha()
  148.         );
  149.         $x intval(imagesx($targetImage) / $labelImageData->getWidth() / 2);
  150.         $y imagesy($targetImage) - $label->getMargin()->getBottom();
  151.         if (LabelAlignment::Left === $label->getAlignment()) {
  152.             $x $label->getMargin()->getLeft();
  153.         } elseif (LabelAlignment::Right === $label->getAlignment()) {
  154.             $x imagesx($targetImage) - $labelImageData->getWidth() - $label->getMargin()->getRight();
  155.         }
  156.         imagettftext($targetImage$label->getFont()->getSize(), 0$x$y$textColor$label->getFont()->getPath(), $label->getText());
  157.         return new GdResult($result->getMatrix(), $targetImage);
  158.     }
  159.     public function validateResult(ResultInterface $resultstring $expectedData): void
  160.     {
  161.         $string $result->getString();
  162.         if (!class_exists(QrReader::class)) {
  163.             throw ValidationException::createForMissingPackage('khanamiryan/qrcode-detector-decoder');
  164.         }
  165.         $reader = new QrReader($stringQrReader::SOURCE_TYPE_BLOB);
  166.         if ($reader->text() !== $expectedData) {
  167.             throw ValidationException::createForInvalidData($expectedDatastrval($reader->text()));
  168.         }
  169.     }
  170. }