svgWithLogo.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <?php
  2. /**
  3. * @created 05.03.2022
  4. * @author smiley <smiley@chillerlan.net>
  5. * @copyright 2022 smiley
  6. * @license MIT
  7. *
  8. * @noinspection PhpComposerExtensionStubsInspection
  9. */
  10. namespace chillerlan\QRCodeExamples;
  11. use chillerlan\QRCode\{QRCode, QRCodeException, QROptions};
  12. use chillerlan\QRCode\Data\QRMatrix;
  13. use chillerlan\QRCode\Common\EccLevel;
  14. use function file_exists, gzencode, header, is_readable, max, min;
  15. require_once __DIR__.'/../vendor/autoload.php';
  16. $data = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
  17. $gzip = true;
  18. $options_arr = [
  19. // SVG logo options (see extended class below)
  20. 'svgLogo' => __DIR__.'/github.svg', // logo from: https://github.com/simple-icons/simple-icons
  21. 'svgLogoScale' => 0.25,
  22. 'svgLogoCssClass' => 'dark',
  23. // QROptions
  24. 'version' => 5,
  25. 'outputType' => QRCode::OUTPUT_CUSTOM,
  26. 'outputInterface' => QRSvgWithLogo::class,
  27. 'imageBase64' => false,
  28. // ECC level H is necessary when using logos
  29. 'eccLevel' => EccLevel::H,
  30. 'addQuietzone' => true,
  31. // if set to true, the light modules won't be rendered
  32. 'imageTransparent' => false,
  33. // empty the default value to remove the fill* attributes from the <path> elements
  34. 'markupDark' => '',
  35. 'markupLight' => '',
  36. // draw the modules as circles isntead of squares
  37. 'drawCircularModules' => true,
  38. 'circleRadius' => 0.45,
  39. // connect paths
  40. 'svgConnectPaths' => true,
  41. // keep modules of thhese types as square
  42. 'keepAsSquare' => [
  43. QRMatrix::M_FINDER|QRMatrix::IS_DARK,
  44. QRMatrix::M_FINDER_DOT,
  45. QRMatrix::M_ALIGNMENT|QRMatrix::IS_DARK,
  46. ],
  47. // https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
  48. 'svgDefs' => '
  49. <linearGradient id="gradient" x1="100%" y2="100%">
  50. <stop stop-color="#D70071" offset="0"/>
  51. <stop stop-color="#9C4E97" offset="0.5"/>
  52. <stop stop-color="#0035A9" offset="1"/>
  53. </linearGradient>
  54. <style><![CDATA[
  55. .dark{fill: url(#gradient);}
  56. .light{fill: #eaeaea;}
  57. ]]></style>',
  58. ];
  59. // augment the QROptions class
  60. $options = new class ($options_arr) extends QROptions{
  61. // path to svg logo
  62. protected string $svgLogo;
  63. // logo scale in % of QR Code size, clamped to 10%-30%
  64. protected float $svgLogoScale = 0.20;
  65. // css class for the logo (defined in $svgDefs)
  66. protected string $svgLogoCssClass = '';
  67. // check logo
  68. protected function set_svgLogo(string $svgLogo):void{
  69. if(!file_exists($svgLogo) || !is_readable($svgLogo)){
  70. throw new QRCodeException('invalid svg logo');
  71. }
  72. // @todo: validate svg
  73. $this->svgLogo = $svgLogo;
  74. }
  75. // clamp logo scale
  76. protected function set_svgLogoScale(float $svgLogoScale):void{
  77. $this->svgLogoScale = max(0.05, min(0.3, $svgLogoScale));
  78. }
  79. };
  80. $qrcode = (new QRCode($options))->render($data);
  81. header('Content-type: image/svg+xml');
  82. if($gzip){
  83. header('Vary: Accept-Encoding');
  84. header('Content-Encoding: gzip');
  85. $qrcode = gzencode($qrcode, 9);
  86. }
  87. echo $qrcode;