* @copyright 2022 smiley
* @license MIT
*
* @noinspection PhpComposerExtensionStubsInspection
*/
use chillerlan\QRCode\{QRCode, QRCodeException, QROptions};
use chillerlan\QRCode\Common\EccLevel;
use chillerlan\QRCode\Data\QRMatrix;
use chillerlan\QRCode\Output\{QROutputInterface, QRMarkupSVG};
require_once __DIR__.'/../vendor/autoload.php';
/*
* Class definition
*/
/**
* Create SVG QR Codes with embedded logos (that are also SVG)
*/
class QRSvgWithLogo extends QRMarkupSVG{
/**
* @inheritDoc
*/
protected function paths():string{
$size = (int)ceil($this->moduleCount * $this->options->svgLogoScale);
// we're calling QRMatrix::setLogoSpace() manually, so QROptions::$addLogoSpace has no effect here
$this->matrix->setLogoSpace($size, $size);
$svg = parent::paths();
$svg .= $this->getLogo();
return $svg;
}
/**
* @inheritDoc
*/
protected function path(string $path, int $M_TYPE):string{
// omit the "fill" and "opacity" attributes on the path element
return sprintf('', $this->getCssClass($M_TYPE), $path);
}
/**
* returns a element that contains the SVG logo and positions it properly within the QR Code
*
* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform
*/
protected function getLogo():string{
// @todo: customize the element to your liking (css class, style...)
return sprintf(
'%5$s%5$s %4$s%5$s',
($this->moduleCount - ($this->moduleCount * $this->options->svgLogoScale)) / 2,
$this->options->svgLogoScale,
$this->options->svgLogoCssClass,
file_get_contents($this->options->svgLogo),
$this->options->eol
);
}
}
/**
* augment the QROptions class
*/
class SVGWithLogoOptions extends QROptions{
// path to svg logo
protected string $svgLogo;
// logo scale in % of QR Code size, clamped to 10%-30%
protected float $svgLogoScale = 0.20;
// css class for the logo (defined in $svgDefs)
protected string $svgLogoCssClass = '';
// check logo
protected function set_svgLogo(string $svgLogo):void{
if(!file_exists($svgLogo) || !is_readable($svgLogo)){
throw new QRCodeException('invalid svg logo');
}
// @todo: validate svg
$this->svgLogo = $svgLogo;
}
// clamp logo scale
protected function set_svgLogoScale(float $svgLogoScale):void{
$this->svgLogoScale = max(0.05, min(0.3, $svgLogoScale));
}
}
/*
* Runtime
*/
$options = new SVGWithLogoOptions([
// SVG logo options (see extended class below)
'svgLogo' => __DIR__.'/github.svg', // logo from: https://github.com/simple-icons/simple-icons
'svgLogoScale' => 0.25,
'svgLogoCssClass' => 'dark',
// QROptions
'version' => 5,
'outputType' => QROutputInterface::CUSTOM,
'outputInterface' => QRSvgWithLogo::class,
'imageBase64' => false,
// ECC level H is necessary when using logos
'eccLevel' => EccLevel::H,
'addQuietzone' => true,
// if set to true, the light modules won't be rendered
'drawLightModules' => true,
// draw the modules as circles isntead of squares
'drawCircularModules' => true,
'circleRadius' => 0.45,
// connect paths
'connectPaths' => true,
// keep modules of thhese types as square
'keepAsSquare' => [
QRMatrix::M_FINDER|QRMatrix::IS_DARK,
QRMatrix::M_FINDER_DOT,
QRMatrix::M_ALIGNMENT|QRMatrix::IS_DARK,
],
// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
'svgDefs' => '
',
]);
$qrcode = (new QRCode($options))->render('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
if(php_sapi_name() !== 'cli'){
header('Content-type: image/svg+xml');
if(extension_loaded('zlib')){
header('Vary: Accept-Encoding');
header('Content-Encoding: gzip');
$qrcode = gzencode($qrcode, 9);
}
}
echo $qrcode;
exit;