QRMarkup.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <?php
  2. /**
  3. * Class QRMarkup
  4. *
  5. * @filesource QRMarkup.php
  6. * @created 17.12.2016
  7. * @package chillerlan\QRCode\Output
  8. * @author Smiley <smiley@chillerlan.net>
  9. * @copyright 2016 Smiley
  10. * @license MIT
  11. */
  12. namespace chillerlan\QRCode\Output;
  13. use chillerlan\QRCode\QRCode;
  14. /**
  15. * Converts the matrix into markup types: HTML, SVG, ...
  16. */
  17. class QRMarkup extends QROutputAbstract{
  18. /**
  19. * @return string
  20. */
  21. public function dump(){
  22. switch($this->options->outputType){
  23. case QRCode::OUTPUT_MARKUP_HTML:
  24. return $this->toHTML();
  25. case QRCode::OUTPUT_MARKUP_SVG :
  26. default:
  27. return $this->toSVG();
  28. }
  29. }
  30. /**
  31. * @return string|bool
  32. */
  33. protected function toHTML(){
  34. $html = '';
  35. foreach($this->matrix->matrix() as $row){
  36. $html .= '<div>';
  37. foreach($row as $pixel){
  38. $html .= '<span style="background: '.($this->options->moduleValues[$pixel] ?: 'lightgrey').';"></span>';
  39. }
  40. $html .= '</div>';
  41. $html .= $this->options->eol;
  42. }
  43. if($this->options->cachefile){
  44. $html = '<!DOCTYPE html><head><meta charset="UTF-8"></head><body>'.$this->options->eol.$html.'</body>';
  45. return $this->saveToFile($html);
  46. }
  47. return $html;
  48. }
  49. /**
  50. * @link https://github.com/codemasher/php-qrcode/pull/5
  51. *
  52. * @return string|bool
  53. */
  54. protected function toSVG(){
  55. $length = ($this->moduleCount + ($this->options->addQuietzone ? 8 : 0)) * $this->options->scale;
  56. // svg header
  57. $svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="'.$length.'" height="'.$length.'" viewBox="0 0 '.$length.' '.$length.'">'.$this->options->eol.
  58. '<defs><style>rect{shape-rendering:crispEdges}</style></defs>'.$this->options->eol;
  59. // @todo: optimize -> see https://github.com/alexeyten/qr-image/blob/master/lib/vector.js
  60. foreach($this->options->moduleValues as $key => $value){
  61. // fallback
  62. if(is_bool($value)){
  63. $value = $value ? '#000' : '#fff';
  64. }
  65. // svg body
  66. foreach($this->matrix->matrix() as $y => $row){
  67. //we'll combine active blocks within a single row as a lightweight compression technique
  68. $from = -1;
  69. $count = 0;
  70. foreach($row as $x => $pixel){
  71. if($pixel === $key){
  72. $count++;
  73. if($from < 0){
  74. $from = $x;
  75. }
  76. }
  77. elseif($from >= 0){
  78. $svg .= '<rect x="'.($from * $this->options->scale).'" y="'.($y * $this->options->scale)
  79. .'" width="'.($this->options->scale * $count).'" height="'.$this->options->scale.'" fill="'.$value.'"'
  80. .(trim($this->options->cssClass) !== '' ? ' class="'.$this->options->cssClass.'"' :'').' />'
  81. .$this->options->eol;
  82. // reset count
  83. $from = -1;
  84. $count = 0;
  85. }
  86. }
  87. // close off the row, if applicable
  88. if($from >= 0){
  89. $svg .= '<rect x="'.($from * $this->options->scale).'" y="'.($y * $this->options->scale)
  90. .'" width="'.($this->options->scale * $count).'" height="'.$this->options->scale.'" class="'.$this->options->cssClass.'" fill="'.$value.'" />'.$this->options->eol;
  91. }
  92. }
  93. }
  94. // close svg
  95. $svg .= '</svg>'.$this->options->eol;
  96. // if saving to file, append the correct headers
  97. if($this->options->cachefile){
  98. $svg = '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'.$this->options->eol.$svg;
  99. return $this->saveToFile($svg);
  100. }
  101. return $svg;
  102. }
  103. }