-
-
Notifications
You must be signed in to change notification settings - Fork 306
/
Copy pathsvgWithLogo.php
156 lines (126 loc) · 4.11 KB
/
svgWithLogo.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?php
/**
* SVG with logo example
*
* @created 05.03.2022
* @author smiley <[email protected]>
* @copyright 2022 smiley
* @license MIT
*
* @noinspection PhpComposerExtensionStubsInspection
*/
declare(strict_types=1);
use chillerlan\QRCode\{QRCode, QRCodeException, QROptions};
use chillerlan\QRCode\Common\EccLevel;
use chillerlan\QRCode\Data\QRMatrix;
use chillerlan\QRCode\Output\QRMarkupSVG;
require_once __DIR__.'/../vendor/autoload.php';
/*
* Class definition
*/
/**
* Create SVG QR Codes with embedded logos (that are also SVG)
*/
class QRSvgWithLogo extends QRMarkupSVG{
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;
}
protected function path(string $path, int $M_TYPE):string{
// omit the "fill" and "opacity" attributes on the path element
return sprintf('<path class="%s" d="%s"/>', $this->getCssClass($M_TYPE), $path);
}
/**
* 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
*
* @property string $svgLogo
* @property float $svgLogoScale
* @property string $svgLogoCssClass
*/
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)
$options->svgLogo = __DIR__.'/github.svg'; // logo from: https://github.com/simple-icons/simple-icons
$options->svgLogoScale = 0.25;
$options->svgLogoCssClass = 'dark';
// QROptions
$options->version = 5;
$options->outputInterface = QRSvgWithLogo::class;
$options->outputBase64 = false;
$options->eccLevel = EccLevel::H; // ECC level H is necessary when using logos
$options->addQuietzone = true;
$options->drawLightModules = true;
$options->connectPaths = true;
$options->drawCircularModules = true;
$options->circleRadius = 0.45;
$options->keepAsSquare = [
QRMatrix::M_FINDER_DARK,
QRMatrix::M_FINDER_DOT,
QRMatrix::M_ALIGNMENT_DARK,
];
// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
$options->svgDefs = '
<linearGradient id="gradient" x1="100%" y2="100%">
<stop stop-color="#D70071" offset="0"/>
<stop stop-color="#9C4E97" offset="0.5"/>
<stop stop-color="#0035A9" offset="1"/>
</linearGradient>
<style><![CDATA[
.dark{fill: url(#gradient);}
.light{fill: #eaeaea;}
]]></style>';
$out = (new QRCode($options))->render('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
if(PHP_SAPI !== 'cli'){
header('Content-type: image/svg+xml');
if(extension_loaded('zlib')){
header('Vary: Accept-Encoding');
header('Content-Encoding: gzip');
$out = gzencode($out, 9);
}
}
echo $out;
exit;