BaconQrCodeProvider.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. namespace RobThree\Auth\Providers\Qr;
  3. use BaconQrCode\Writer;
  4. use BaconQrCode\Renderer\ImageRenderer;
  5. use BaconQrCode\Renderer\RendererStyle\RendererStyle;
  6. use BaconQrCode\Renderer\RendererStyle\Fill;
  7. use BaconQrCode\Renderer\Color\Rgb;
  8. use BaconQrCode\Renderer\RendererStyle\EyeFill;
  9. use BaconQrCode\Renderer\Image\EpsImageBackEnd;
  10. use BaconQrCode\Renderer\Image\ImageBackEndInterface;
  11. use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
  12. use BaconQrCode\Renderer\Image\SvgImageBackEnd;
  13. class BaconQrCodeProvider implements IQRCodeProvider
  14. {
  15. private $borderWidth = 4; // default from Bacon QR Code
  16. private $backgroundColour;
  17. private $foregroundColour;
  18. private $format;
  19. /**
  20. * Ensure we using the latest Bacon QR Code and specify default options
  21. *
  22. * @param int $borderWidth space around the QR code, 4 is the default from Bacon QR Code
  23. * @param string $backgroundColour hex reference for the background colour
  24. * @param string $foregroundColour hex reference for the foreground colour
  25. * @param string $format the desired output, png or svg
  26. */
  27. public function __construct($borderWidth = 4, $backgroundColour = '#ffffff', $foregroundColour = '#000000', $format = 'png')
  28. {
  29. if (! class_exists(ImagickImageBackEnd::class)) {
  30. throw new \RuntimeException('Make sure you are using version 2 of Bacon QR Code');
  31. }
  32. $this->borderWidth = $borderWidth;
  33. $this->backgroundColour = $this->handleColour($backgroundColour);
  34. $this->foregroundColour = $this->handleColour($foregroundColour);
  35. $this->format = strtolower($format);
  36. }
  37. /**
  38. * Standard functions from IQRCodeProvider
  39. */
  40. public function getMimeType()
  41. {
  42. switch ($this->format) {
  43. case 'png':
  44. return 'image/png';
  45. case 'gif':
  46. return 'image/gif';
  47. case 'jpg':
  48. case 'jpeg':
  49. return 'image/jpeg';
  50. case 'svg':
  51. return 'image/svg+xml';
  52. case 'eps':
  53. return 'application/postscript';
  54. }
  55. throw new \RuntimeException(sprintf('Unknown MIME-type: %s', $this->format));
  56. }
  57. public function getQRCodeImage($qrText, $size)
  58. {
  59. switch ($this->format) {
  60. case 'svg':
  61. $backend = new SvgImageBackEnd;
  62. break;
  63. case 'eps':
  64. $backend = new EpsImageBackEnd;
  65. break;
  66. default:
  67. $backend = new ImagickImageBackEnd($this->format);
  68. }
  69. $output = $this->getQRCodeByBackend($qrText, $size, $backend);
  70. if ($this->format == 'svg') {
  71. $svg = explode("\n", $output);
  72. return $svg[1];
  73. }
  74. return $output;
  75. }
  76. /**
  77. * Abstract QR code generation function
  78. * providing colour changing support
  79. */
  80. private function getQRCodeByBackend($qrText, $size, ImageBackEndInterface $backend)
  81. {
  82. $rendererStyleArgs = array($size, $this->borderWidth);
  83. if (is_array($this->foregroundColour) && is_array($this->backgroundColour)) {
  84. $rendererStyleArgs = array_merge($rendererStyleArgs, array(
  85. null,
  86. null,
  87. Fill::withForegroundColor(
  88. new Rgb(...$this->backgroundColour),
  89. new Rgb(...$this->foregroundColour),
  90. new EyeFill(null, null),
  91. new EyeFill(null, null),
  92. new EyeFill(null, null)
  93. )
  94. ));
  95. }
  96. $writer = new Writer(new ImageRenderer(
  97. new RendererStyle(...$rendererStyleArgs),
  98. $backend
  99. ));
  100. return $writer->writeString($qrText);
  101. }
  102. /**
  103. * Ensure colour is an array of three values but also
  104. * accept a string and assume its a 3 or 6 character hex
  105. */
  106. private function handleColour($colour)
  107. {
  108. if (is_string($colour) && $colour[0] == '#') {
  109. $hexToRGB = function ($input) {
  110. // split the array into three chunks
  111. $split = str_split(trim($input, '#'), strlen($input) / 3);
  112. // cope with three character hex reference
  113. // three characters plus a # = 4
  114. if (strlen($input) == 4) {
  115. array_walk($split, function (&$character) {
  116. $character = str_repeat($character, 2);
  117. });
  118. }
  119. // convert hex to rgb
  120. return array_map('hexdec', $split);
  121. };
  122. return $hexToRGB($colour);
  123. }
  124. if (is_array($colour) && count($colour) == 3) {
  125. return $colour;
  126. }
  127. throw new \RuntimeException('Invalid colour value');
  128. }
  129. }