xref: /plugin/dw2pdf/vendor/mpdf/qrcode/src/Output/Svg.php (revision fb347f35dc824cf59875d883dbf86d311f54de06)
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