| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  |  * Class QRMarkup | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  * @created      17.12.2016 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  * @author       Smiley <[email protected]> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  * @copyright    2016 Smiley | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  * @license      MIT | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | namespace chillerlan\QRCode\Output; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | use chillerlan\QRCode\Data\QRMatrix; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | use chillerlan\QRCode\QRCode; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | use function implode, is_string, ksort, sprintf, strip_tags, trim; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |  * Converts the matrix into markup types: HTML, SVG, ... | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  | class QRMarkup extends QROutputAbstract{ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  | 	protected string $defaultMode = QRCode::OUTPUT_MARKUP_SVG; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  | 	/** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  | 	 * @inheritDoc | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  | 	 */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  | 	protected function setModuleValues():void{ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  | 		foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  | 			$v = $this->options->moduleValues[$M_TYPE] ?? null; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  | 			if(!is_string($v)){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  | 				$this->moduleValues[$M_TYPE] = $defaultValue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  | 					? $this->options->markupDark | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  | 					: $this->options->markupLight; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  | 			} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  | 			else{ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  | 				$this->moduleValues[$M_TYPE] = trim(strip_tags($v), " '\"\r\n\t"); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  | 			} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  | 	} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  | 	/** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  | 	 * HTML output | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  | 	 */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  | 	protected function html(string $file = null):string{ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  | 		$html = empty($this->options->cssClass) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  | 			? '<div>' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  | 			: sprintf('<div class="%s">', $this->options->cssClass); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  | 		$html .= $this->options->eol; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  | 		foreach($this->matrix->matrix() as $row){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  | 			$html .= '<div>'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  | 			foreach($row as $M_TYPE){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  | 				$html .= sprintf('<span style="background: %s;"></span>', $this->moduleValues[$M_TYPE]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  | 			} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  | 			$html .= '</div>'.$this->options->eol; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  | 		$html .= '</div>'.$this->options->eol; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  | 		if($file !== null){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  | 			return sprintf( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  | 				'<!DOCTYPE html><head><meta charset="UTF-8"><title>QR Code</title></head><body>%s</body>', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  | 				$this->options->eol.$html | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  | 			); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  | 		return $html; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  | 	} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  | 	/** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  | 	 * SVG output | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  | 	 * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  | 	 * @see https://github.com/codemasher/php-qrcode/pull/5 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  | 	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  | 	 * @see https://www.sarasoueidan.com/demos/interactive-svg-coordinate-system/ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  | 	 */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  | 	protected function svg(string $file = null):string{ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  | 		$svg = $this->svgHeader(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  | 		if(!empty($this->options->svgDefs)){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  | 			$svg .= sprintf('<defs>%1$s%2$s</defs>%2$s', $this->options->svgDefs, $this->options->eol); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  | 		$svg .= $this->svgPaths(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  | 		// close svg | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  | 		$svg .= sprintf('%1$s</svg>%1$s', $this->options->eol); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  | 		// transform to data URI only when not saving to file | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  | 		if($file === null && $this->options->imageBase64){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  | 			$svg = $this->base64encode($svg, 'image/svg+xml'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  | 		return $svg; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  | 	} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  | 	/** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  | 	 * returns the <svg> header with the given options parsed | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 108 |  |  | 	 */ | 
            
                                                                        
                            
            
                                    
            
            
                | 109 |  |  | 	protected function svgHeader():string{ | 
            
                                                                        
                            
            
                                    
            
            
                | 110 |  |  | 		$width  = $this->options->svgWidth !== null ? sprintf(' width="%s"', $this->options->svgWidth) : ''; | 
            
                                                                        
                            
            
                                    
            
            
                | 111 |  |  | 		$height = $this->options->svgHeight !== null ? sprintf(' height="%s"', $this->options->svgHeight) : ''; | 
            
                                                                        
                            
            
                                    
            
            
                | 112 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 113 |  |  | 		/** @noinspection HtmlUnknownAttribute */ | 
            
                                                                        
                            
            
                                    
            
            
                | 114 |  |  | 		return sprintf( | 
            
                                                                        
                            
            
                                    
            
            
                | 115 |  |  | 			'<?xml version="1.0" encoding="UTF-8"?>%6$s'. | 
            
                                                                        
                            
            
                                    
            
            
                | 116 |  |  | 			'<svg xmlns="http://www.w3.org/2000/svg" class="qr-svg %1$s" viewBox="0 0 %2$s %2$s" preserveAspectRatio="%3$s"%4$s%5$s>%6$s', | 
            
                                                                        
                            
            
                                    
            
            
                | 117 |  |  | 			$this->options->cssClass, | 
            
                                                                        
                            
            
                                    
            
            
                | 118 |  |  | 			$this->options->svgViewBoxSize ?? $this->moduleCount, | 
            
                                                                        
                            
            
                                    
            
            
                | 119 |  |  | 			$this->options->svgPreserveAspectRatio, | 
            
                                                                        
                            
            
                                    
            
            
                | 120 |  |  | 			$width, | 
            
                                                                        
                            
            
                                    
            
            
                | 121 |  |  | 			$height, | 
            
                                                                        
                            
            
                                    
            
            
                | 122 |  |  | 			$this->options->eol | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  | 		); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  | 	} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  | 	/** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  | 	 * returns one or more SVG <path> elements | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  | 	 * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  | 	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  | 	 */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  | 	protected function svgPaths():string{ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  | 		$paths = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  | 		// collect the modules for each type | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  | 		foreach($this->matrix->matrix() as $y => $row){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  | 			foreach($row as $x => $M_TYPE){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  | 				if($this->options->svgConnectPaths && !$this->matrix->checkTypes($x, $y, $this->options->svgExcludeFromConnect)){ | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  | 					// to connect paths we'll redeclare the $M_TYPE to data only | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  | 					$M_TYPE = QRMatrix::M_DATA; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  | 					if($this->matrix->check($x, $y)){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  | 						$M_TYPE |= QRMatrix::IS_DARK; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  | 					} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  | 				} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  | 				// collect the modules per $M_TYPE | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  | 				$paths[$M_TYPE][] = $this->svgModule($x, $y); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  | 			} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  | 		// beautify output | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  | 		ksort($paths); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  | 		$svg = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  | 		// create the path elements | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  | 		foreach($paths as $M_TYPE => $path){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  | 			$path = trim(implode(' ', $path)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  | 			if(empty($path)){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  | 				continue; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  | 			} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  | 			$cssClass = implode(' ', [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  | 				'qr-'.$M_TYPE, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  | 				($M_TYPE & QRMatrix::IS_DARK) === QRMatrix::IS_DARK ? 'dark' : 'light', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  | 				$this->options->cssClass, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  | 			]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  | 			$format = empty($this->moduleValues[$M_TYPE]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  | 				? '<path class="%1$s" d="%2$s"/>' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  | 				: '<path class="%1$s" fill="%3$s" fill-opacity="%4$s" d="%2$s"/>'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  | 			$svg[] = sprintf($format, $cssClass, $path, $this->moduleValues[$M_TYPE], $this->options->svgOpacity); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  | 		return implode($this->options->eol, $svg); | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  | 	} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  | 	/** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  | 	 * returns a path segment for a single module | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  | 	 * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  | 	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  | 	 */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  | 	protected function svgModule(int $x, int $y):string{ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  | 		if($this->options->imageTransparent && !$this->matrix->check($x, $y)){ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  | 			return ''; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  | 		if($this->options->svgDrawCircularModules && !$this->matrix->checkTypes($x, $y, $this->options->svgKeepAsSquare)){ | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  | 			$r = $this->options->svgCircleRadius; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  | 			return sprintf( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  | 				'M%1$s %2$s a%3$s %3$s 0 1 0 %4$s 0 a%3$s,%3$s 0 1 0 -%4$s 0Z', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  | 				($x + 0.5 - $r), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  | 				($y + 0.5), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  | 				$r, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 |  |  | 				($r * 2) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  | 			); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  | 		} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 |  |  | 		return sprintf('M%1$s %2$s h%3$s v1 h-%4$sZ', $x, $y, 1, 1); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  | 	} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 208 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 209 |  |  |  |