1*fb347f35SAndreas Gohr<?php 2*fb347f35SAndreas Gohr 3*fb347f35SAndreas Gohrnamespace Mpdf\QrCode\Output; 4*fb347f35SAndreas Gohr 5*fb347f35SAndreas Gohruse Mpdf\QrCode\QrCode; 6*fb347f35SAndreas Gohruse SimpleXMLElement; 7*fb347f35SAndreas Gohr 8*fb347f35SAndreas Gohrclass Svg 9*fb347f35SAndreas Gohr{ 10*fb347f35SAndreas Gohr 11*fb347f35SAndreas Gohr /** 12*fb347f35SAndreas Gohr * @param QrCode $qrCode QR code instance 13*fb347f35SAndreas Gohr * @param int $size The width / height of the resulting SVG 14*fb347f35SAndreas Gohr * @param string $background The background color, e. g. "white", "rgb(0,0,0)" or "cmyk(0,0,0,0)" 15*fb347f35SAndreas Gohr * @param string $color The foreground and border color, e. g. "black", "rgb(255,255,255)" or "cmyk(0,0,0,100)" 16*fb347f35SAndreas Gohr * 17*fb347f35SAndreas Gohr * @return string Binary image data 18*fb347f35SAndreas Gohr */ 19*fb347f35SAndreas Gohr public function output(QrCode $qrCode, $size = 100, $background = 'white', $color = 'black') 20*fb347f35SAndreas Gohr { 21*fb347f35SAndreas Gohr $qrSize = $qrCode->getQrSize(); 22*fb347f35SAndreas Gohr $final = $qrCode->getFinal(); 23*fb347f35SAndreas Gohr 24*fb347f35SAndreas Gohr if ($qrCode->isBorderDisabled()) { 25*fb347f35SAndreas Gohr $minSize = 4; 26*fb347f35SAndreas Gohr $maxSize = $qrSize - 4; 27*fb347f35SAndreas Gohr } else { 28*fb347f35SAndreas Gohr $minSize = 0; 29*fb347f35SAndreas Gohr $maxSize = $qrSize; 30*fb347f35SAndreas Gohr } 31*fb347f35SAndreas Gohr 32*fb347f35SAndreas Gohr $rectSize = $size / ($maxSize - $minSize); 33*fb347f35SAndreas Gohr 34*fb347f35SAndreas Gohr $svg = new SimpleXMLElement('<svg></svg>'); 35*fb347f35SAndreas Gohr $svg->addAttribute('version', '1.1'); 36*fb347f35SAndreas Gohr $svg->addAttribute('xmlns', 'http://www.w3.org/2000/svg'); 37*fb347f35SAndreas Gohr $svg->addAttribute('width', $size); 38*fb347f35SAndreas Gohr $svg->addAttribute('height', $size); 39*fb347f35SAndreas Gohr 40*fb347f35SAndreas Gohr $this->addChild( 41*fb347f35SAndreas Gohr $svg, 42*fb347f35SAndreas Gohr 'rect', 43*fb347f35SAndreas Gohr [ 44*fb347f35SAndreas Gohr 'x' => 0, 45*fb347f35SAndreas Gohr 'y' => 0, 46*fb347f35SAndreas Gohr 'width' => $size, 47*fb347f35SAndreas Gohr 'height' => $size, 48*fb347f35SAndreas Gohr 'fill' => $background, 49*fb347f35SAndreas Gohr ] 50*fb347f35SAndreas Gohr ); 51*fb347f35SAndreas Gohr 52*fb347f35SAndreas Gohr for ($row = $minSize; $row < $maxSize; $row++) { 53*fb347f35SAndreas Gohr // Simple compression: pixels in a row will be compressed into the same rectangle. 54*fb347f35SAndreas Gohr $startX = null; 55*fb347f35SAndreas Gohr $y = ($row - $minSize) * $rectSize; 56*fb347f35SAndreas Gohr for ($column = $minSize; $column < $maxSize; $column++) { 57*fb347f35SAndreas Gohr $x = ($column - $minSize) * $rectSize; 58*fb347f35SAndreas Gohr if ($final[$column + $row * $qrSize + 1]) { 59*fb347f35SAndreas Gohr if ($startX === null) { 60*fb347f35SAndreas Gohr $startX = $x; 61*fb347f35SAndreas Gohr } 62*fb347f35SAndreas Gohr } elseif ($startX !== null) { 63*fb347f35SAndreas Gohr $this->addChild( 64*fb347f35SAndreas Gohr $svg, 65*fb347f35SAndreas Gohr 'rect', 66*fb347f35SAndreas Gohr [ 67*fb347f35SAndreas Gohr 'x' => $startX, 68*fb347f35SAndreas Gohr 'y' => $y, 69*fb347f35SAndreas Gohr 'width' => $x - $startX, 70*fb347f35SAndreas Gohr 'height' => $rectSize, 71*fb347f35SAndreas Gohr 'fill' => $color, 72*fb347f35SAndreas Gohr ] 73*fb347f35SAndreas Gohr ); 74*fb347f35SAndreas Gohr $startX = null; 75*fb347f35SAndreas Gohr } 76*fb347f35SAndreas Gohr } 77*fb347f35SAndreas Gohr 78*fb347f35SAndreas Gohr if ($startX !== null) { 79*fb347f35SAndreas Gohr $x = ($column - $minSize) * $rectSize; 80*fb347f35SAndreas Gohr $this->addChild( 81*fb347f35SAndreas Gohr $svg, 82*fb347f35SAndreas Gohr 'rect', 83*fb347f35SAndreas Gohr [ 84*fb347f35SAndreas Gohr 'x' => $startX, 85*fb347f35SAndreas Gohr 'y' => $y, 86*fb347f35SAndreas Gohr 'width' => $x - $startX, 87*fb347f35SAndreas Gohr 'height' => $rectSize, 88*fb347f35SAndreas Gohr 'fill' => $color, 89*fb347f35SAndreas Gohr ] 90*fb347f35SAndreas Gohr ); 91*fb347f35SAndreas Gohr } 92*fb347f35SAndreas Gohr } 93*fb347f35SAndreas Gohr 94*fb347f35SAndreas Gohr for ($column = $minSize; $column < $maxSize; $column++) { 95*fb347f35SAndreas Gohr // Simple compression: pixels in a column will be compressed into the same rectangle. 96*fb347f35SAndreas Gohr $startY = null; 97*fb347f35SAndreas Gohr $x = ($column - $minSize) * $rectSize; 98*fb347f35SAndreas Gohr for ($row = $minSize; $row < $maxSize; $row++) { 99*fb347f35SAndreas Gohr $y = ($row - $minSize) * $rectSize; 100*fb347f35SAndreas Gohr if ($final[$column + $row * $qrSize + 1]) { 101*fb347f35SAndreas Gohr if ($startY === null) { 102*fb347f35SAndreas Gohr $startY = $y; 103*fb347f35SAndreas Gohr } 104*fb347f35SAndreas Gohr } elseif ($startY !== null) { 105*fb347f35SAndreas Gohr if ($startY < $y - $rectSize) { 106*fb347f35SAndreas Gohr // Only drawn 2+ columns 107*fb347f35SAndreas Gohr $this->addChild( 108*fb347f35SAndreas Gohr $svg, 109*fb347f35SAndreas Gohr 'rect', 110*fb347f35SAndreas Gohr [ 111*fb347f35SAndreas Gohr 'x' => $x, 112*fb347f35SAndreas Gohr 'y' => $startY, 113*fb347f35SAndreas Gohr 'width' => $rectSize, 114*fb347f35SAndreas Gohr 'height' => $y - $startY, 115*fb347f35SAndreas Gohr 'fill' => $color, 116*fb347f35SAndreas Gohr ] 117*fb347f35SAndreas Gohr ); 118*fb347f35SAndreas Gohr } 119*fb347f35SAndreas Gohr $startY = null; 120*fb347f35SAndreas Gohr } 121*fb347f35SAndreas Gohr } 122*fb347f35SAndreas Gohr 123*fb347f35SAndreas Gohr if ($startY !== null) { 124*fb347f35SAndreas Gohr $y = ($row - $minSize) * $rectSize; 125*fb347f35SAndreas Gohr $this->addChild( 126*fb347f35SAndreas Gohr $svg, 127*fb347f35SAndreas Gohr 'rect', 128*fb347f35SAndreas Gohr [ 129*fb347f35SAndreas Gohr 'x' => $x, 130*fb347f35SAndreas Gohr 'y' => $startY, 131*fb347f35SAndreas Gohr 'width' => $rectSize, 132*fb347f35SAndreas Gohr 'height' => $y - $startY, 133*fb347f35SAndreas Gohr 'fill' => $color, 134*fb347f35SAndreas Gohr ] 135*fb347f35SAndreas Gohr ); 136*fb347f35SAndreas Gohr } 137*fb347f35SAndreas Gohr } 138*fb347f35SAndreas Gohr 139*fb347f35SAndreas Gohr return $svg->asXML(); 140*fb347f35SAndreas Gohr } 141*fb347f35SAndreas Gohr 142*fb347f35SAndreas Gohr 143*fb347f35SAndreas Gohr /** 144*fb347f35SAndreas Gohr * Adds a child with the given attributes 145*fb347f35SAndreas Gohr * 146*fb347f35SAndreas Gohr * @param SimpleXMLElement $svg 147*fb347f35SAndreas Gohr * @param string $name 148*fb347f35SAndreas Gohr * @param array $attributes 149*fb347f35SAndreas Gohr * 150*fb347f35SAndreas Gohr * @return SimpleXMLElement 151*fb347f35SAndreas Gohr */ 152*fb347f35SAndreas Gohr public function addChild(SimpleXMLElement $svg, $name, array $attributes = []) 153*fb347f35SAndreas Gohr { 154*fb347f35SAndreas Gohr $child = $svg->addChild($name); 155*fb347f35SAndreas Gohr 156*fb347f35SAndreas Gohr foreach ($attributes as $key => $value) { 157*fb347f35SAndreas Gohr $child->addAttribute((string) $key, (string) $value); 158*fb347f35SAndreas Gohr } 159*fb347f35SAndreas Gohr 160*fb347f35SAndreas Gohr return $child; 161*fb347f35SAndreas Gohr } 162*fb347f35SAndreas Gohr} 163