<?php
namespace HeroQR\Customs\ShapeDrawers;
use Endroid\QrCode\Color\ColorInterface;
/**
* Provides static methods to define and draw QR code shapes as SVG elements using <use>
*/
class SvgShapeDrawer
{
/**
* Draws a star shape on the image
*/
public static function drawStar(
\SimpleXMLElement $baseImage,
int $rowIndex,
int $colIndex,
int $baseBlockSize,
ColorInterface $foregroundColor
): void
{
self::render($baseImage, __FUNCTION__, function ($defs, $blockSize) {
$points = [];
for ($i = 0; $i < 10; $i++) {
$angle = ($i * M_PI / 5) + (M_PI / 2);
$radius = ($i % 2 === 0) ? $blockSize / 2 : $blockSize / 4;
$x = $radius * cos($angle);
$y = -($radius * sin($angle));
$points[] = round($x, 2) . ',' . round($y, 2);
}
$star = $defs->addChild('polygon');
$star->addAttribute('points', implode(' ', $points));
return $star;
}, $rowIndex, $colIndex, $baseBlockSize, $foregroundColor);
}
/**
* Draws a square shape on the image
*/
public static function drawSquare(
\SimpleXMLElement $baseImage,
int $rowIndex,
int $colIndex,
int $baseBlockSize,
ColorInterface $foregroundColor
): void
{
self::render($baseImage, __FUNCTION__, function ($defs, $blockSize) {
$square = $defs->addChild('rect');
$square->addAttribute('x', (string)-($blockSize / 2));
$square->addAttribute('y', (string)-($blockSize / 2));
$square->addAttribute('width', (string)$blockSize);
$square->addAttribute('height', (string)$blockSize);
return $square;
}, $rowIndex, $colIndex, $baseBlockSize, $foregroundColor);
}
/**
* Draws a circle shape on the image
*/
public static function drawCircle(
\SimpleXMLElement $baseImage,
int $rowIndex,
int $colIndex,
int $baseBlockSize,
ColorInterface $foregroundColor
): void
{
self::render($baseImage, __FUNCTION__, function ($defs, $blockSize) {
$circle = $defs->addChild('circle');
$circle->addAttribute('cx', '0');
$circle->addAttribute('cy', '0');
$circle->addAttribute('r', (string)(($blockSize * 0.8) / 2));
return $circle;
}, $rowIndex, $colIndex, $baseBlockSize, $foregroundColor);
}
/**
* Draws a diamond shape on the image
*/
public static function drawDiamond(
\SimpleXMLElement $baseImage,
int $rowIndex,
int $colIndex,
int $baseBlockSize,
ColorInterface $foregroundColor
): void
{
self::render($baseImage, __FUNCTION__, function ($defs, $blockSize) {
$halfSize = $blockSize / 2.2;
$points = "0," . (-$halfSize) . " " . $halfSize . ",0 0," . $halfSize . " " . (-$halfSize) . ",0";
$el = $defs->addChild('polygon');
$el->addAttribute('points', $points);
return $el;
}, $rowIndex, $colIndex, $baseBlockSize, $foregroundColor);
}
/**
* Renders the SVG shape definition in <defs> or places a <use> reference at the target position
*/
private static function render(
\SimpleXMLElement $baseImage,
string $methodName,
callable $definitionCallback,
int $rowIndex,
int $columnIndex,
int $blockSize,
ColorInterface $foregroundColor
): void
{
$shapeId = 'shape_' . $methodName;
if ($baseImage->getName() === 'defs') {
$el = $definitionCallback($baseImage, $blockSize);
$el->addAttribute('id', $shapeId);
$el->addAttribute('fill', $foregroundColor->getHex());
$alpha = 1 - ($foregroundColor->getAlpha() / 127);
$el->addAttribute('fill-opacity', (string)min(1, max(0, $alpha)));
} else {
$use = $baseImage->addChild('use');
$use->addAttribute('href', '#' . $shapeId);
$x = round(($columnIndex * $blockSize) + ($blockSize / 2), 1);
$y = round(($rowIndex * $blockSize) + ($blockSize / 2), 1);
$use->addAttribute('x', (string)$x);
$use->addAttribute('y', (string)$y);
}
}
}
|