|
@@ -8,19 +8,94 @@
|
|
|
* @noinspection PhpComposerExtensionStubsInspection
|
|
* @noinspection PhpComposerExtensionStubsInspection
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-namespace chillerlan\QRCodeExamples;
|
|
|
|
|
-
|
|
|
|
|
use chillerlan\QRCode\{QRCode, QRCodeException, QROptions};
|
|
use chillerlan\QRCode\{QRCode, QRCodeException, QROptions};
|
|
|
-use chillerlan\QRCode\Data\QRMatrix;
|
|
|
|
|
use chillerlan\QRCode\Common\EccLevel;
|
|
use chillerlan\QRCode\Common\EccLevel;
|
|
|
-use function file_exists, gzencode, header, is_readable, max, min;
|
|
|
|
|
|
|
+use chillerlan\QRCode\Data\QRMatrix;
|
|
|
|
|
+use chillerlan\QRCode\Output\QRMarkupSVG;
|
|
|
|
|
|
|
|
require_once __DIR__.'/../vendor/autoload.php';
|
|
require_once __DIR__.'/../vendor/autoload.php';
|
|
|
|
|
|
|
|
-$data = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
|
|
|
|
|
-$gzip = true;
|
|
|
|
|
|
|
+/*
|
|
|
|
|
+ * 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;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * returns a <g> 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 <g> element to your liking (css class, style...)
|
|
|
|
|
+ return sprintf(
|
|
|
|
|
+ '%5$s<g transform="translate(%1$s %1$s) scale(%2$s)" class="%3$s">%5$s %4$s%5$s</g>',
|
|
|
|
|
+ ($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));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-$options_arr = [
|
|
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Runtime
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+$options = new SVGWithLogoOptions([
|
|
|
// SVG logo options (see extended class below)
|
|
// SVG logo options (see extended class below)
|
|
|
'svgLogo' => __DIR__.'/github.svg', // logo from: https://github.com/simple-icons/simple-icons
|
|
'svgLogo' => __DIR__.'/github.svg', // logo from: https://github.com/simple-icons/simple-icons
|
|
|
'svgLogoScale' => 0.25,
|
|
'svgLogoScale' => 0.25,
|
|
@@ -60,44 +135,21 @@ $options_arr = [
|
|
|
.dark{fill: url(#gradient);}
|
|
.dark{fill: url(#gradient);}
|
|
|
.light{fill: #eaeaea;}
|
|
.light{fill: #eaeaea;}
|
|
|
]]></style>',
|
|
]]></style>',
|
|
|
-];
|
|
|
|
|
-
|
|
|
|
|
-// augment the QROptions class
|
|
|
|
|
-$options = new class ($options_arr) 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{
|
|
|
|
|
|
|
+$qrcode = (new QRCode($options))->render('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
|
|
|
|
|
|
|
|
- if(!file_exists($svgLogo) || !is_readable($svgLogo)){
|
|
|
|
|
- throw new QRCodeException('invalid svg logo');
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // @todo: validate svg
|
|
|
|
|
|
|
|
|
|
- $this->svgLogo = $svgLogo;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+if(php_sapi_name() !== 'cli'){
|
|
|
|
|
+ header('Content-type: image/svg+xml');
|
|
|
|
|
|
|
|
- // clamp logo scale
|
|
|
|
|
- protected function set_svgLogoScale(float $svgLogoScale):void{
|
|
|
|
|
- $this->svgLogoScale = max(0.05, min(0.3, $svgLogoScale));
|
|
|
|
|
|
|
+ if(extension_loaded('zlib')){
|
|
|
|
|
+ header('Vary: Accept-Encoding');
|
|
|
|
|
+ header('Content-Encoding: gzip');
|
|
|
|
|
+ $qrcode = gzencode($qrcode, 9);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-$qrcode = (new QRCode($options))->render($data);
|
|
|
|
|
-
|
|
|
|
|
-header('Content-type: image/svg+xml');
|
|
|
|
|
-
|
|
|
|
|
-if($gzip){
|
|
|
|
|
- header('Vary: Accept-Encoding');
|
|
|
|
|
- header('Content-Encoding: gzip');
|
|
|
|
|
- $qrcode = gzencode($qrcode, 9);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
echo $qrcode;
|
|
echo $qrcode;
|
|
|
|
|
+
|
|
|
|
|
+exit;
|