1<?php 2 3namespace jucksearm\barcode\lib; 4 5use jucksearm\barcode\lib\Barcode2D; 6 7class QRcodeFactory 8{ 9 private $_attributes; 10 private $_borderPx = 1; 11 private $_marginPx = 5; 12 private $_scalePx = 1; 13 14 public function __construct() 15 { 16 $this->_attributes = [ 17 'code' => null, 18 'emblem' => null, 19 'level' => 'L', 20 'file' => null, 21 'size' => 100, 22 'margin' => 1, 23 'color' => '000', 24 ]; 25 } 26 27 public function __set($name, $value) 28 { 29 $setter = 'set' . $name; 30 if (method_exists($this, $setter)) { 31 // set property 32 $this->$setter($value); 33 34 return; 35 } 36 } 37 38 public function __get($name) 39 { 40 $getter = 'get' . $name; 41 if (method_exists($this, $getter)) { 42 // read property 43 return $this->$getter(); 44 } 45 } 46 47 public function setAttribute($name, $value) 48 { 49 if ($value === null) return; 50 51 $this->_attributes[$name] = $value; 52 } 53 54 public function getAttribute($name) 55 { 56 return $this->_attributes[$name]; 57 } 58 59 public function setAttributes($attrs = []) 60 { 61 array_merge($this->_attributes, $attrs); 62 } 63 64 public function getAttributes() 65 { 66 return $this->_attributes; 67 } 68 69 public function setCode($value) 70 { 71 $this->setAttribute('code', $value); 72 return $this; 73 } 74 75 public function getCode() 76 { 77 return $this->getAttribute('code'); 78 } 79 80 public function setEmblem($value) 81 { 82 $this->setAttribute('emblem', $value); 83 return $this; 84 } 85 86 public function getEmblem() 87 { 88 if ($this->getAttribute('emblem') == null) return null; 89 90 $min = 10; 91 $emblem = []; 92 $emblem['image'] = $this->getAttribute('emblem'); 93 $bcd = $this->barcode->getBarcodeArray(); 94 95 $emblem['frame'] = $this->size; 96 $area = floor(($this->scale->size * $bcd['num_cols']) * 0.2); 97 $emblem['area'] = $area < $min ? $min:$area ; 98 $emblem['posX'] = floor(($emblem['frame'] - $emblem['area']) / 2); 99 $emblem['posY'] = $emblem['posX']; 100 101 return (object) $emblem; 102 } 103 104 public function setLevel($value) 105 { 106 if (!in_array($value, ['L','M','Q','H'])) return $this; 107 108 $this->setAttribute('level', $value); 109 return $this; 110 } 111 112 public function getLevel() 113 { 114 return $this->getAttribute('level'); 115 } 116 117 public function setFile($value) 118 { 119 $this->setAttribute('file', $value); 120 return $this; 121 } 122 123 public function getFile() 124 { 125 return $this->getAttribute('file'); 126 } 127 128 public function setSize($value) 129 { 130 $this->setAttribute('size', $value); 131 return $this; 132 } 133 134 public function getSize() 135 { 136 return $this->getAttribute('size') * $this->_scalePx; 137 } 138 139 public function setMargin($value) 140 { 141 $this->setAttribute('margin', $value); 142 return $this; 143 } 144 145 public function getMargin() 146 { 147 return $this->getAttribute('margin'); 148 } 149 150 public function setColor($value) 151 { 152 $this->setAttribute('color', $value); 153 return $this; 154 } 155 156 public function getColor() 157 { 158 return $this->getAttribute('color'); 159 } 160 161 public function getBarcode() 162 { 163 return new Barcode2D($this->code, 'QRCODE,' . $this->level); 164 } 165 166 public function getHexColor() 167 { 168 $color = $this->color; 169 170 return '#'.$color; 171 } 172 173 public function getRgbColor() 174 { 175 $color = $this->color; 176 177 if (strlen($color) > 3) { 178 $r = hexdec(substr($color, 0, 2)); 179 $g = hexdec(substr($color, 2, 2)); 180 $b = hexdec(substr($color, 4, 2)); 181 } else { 182 $r = hexdec(substr($color, 0, 1).substr($color, 0, 1)); 183 $g = hexdec(substr($color, 1, 1).substr($color, 1, 1)); 184 $b = hexdec(substr($color, 2, 1).substr($color, 2, 1)); 185 } 186 187 return [$r, $g, $b]; 188 } 189 190 private function getScale() 191 { 192 $scale = []; 193 $bcd = $this->barcode->getBarcodeArray(); 194 195 if ($this->margin > 0) { 196 $scale['frame'] = $this->size - ($this->_borderPx * 2); 197 $scale['margin'] = round($this->size * ($this->margin / 100)); 198 $scale['area'] = $scale['frame'] - (($scale['margin'] * 2)); 199 $scale['size'] = floor($scale['area'] / $bcd['num_cols']); 200 $scale['posX'] = $scale['margin'] + floor(($scale['area'] - ($bcd['num_cols'] * $scale['size'])) / 2); 201 $scale['posY'] = $scale['posX']; 202 } else { 203 $scale['frame'] = $this->size; 204 $scale['margin'] = 0; 205 $scale['area'] = $this->size; 206 $scale['size'] = floor($scale['area'] / $bcd['num_cols']); 207 $scale['posX'] = floor(($scale['frame'] - ($bcd['num_cols'] * $scale['size'])) / 2); 208 $scale['posY'] = $scale['posX']; 209 } 210 211 if ($this->size < $scale['frame']) 212 throw new \Exception('This size not render.'); 213 214 return (object) $scale; 215 } 216 217 public function getQRcodeHtmlData() 218 { 219 $bcd = $this->barcode->getBarcodeArray(); 220 $color = $this->hexColor; 221 $scale = $this->scale; 222 223 if ($this->margin > 0) { 224 $qrcodeData = '<div style="position:absolute; border: solid '.$this->_borderPx.'px '.$this->hexColor.'; width:'.($this->size - 2).'px; height:'.($this->size - 2).'px">'; 225 } else { 226 $qrcodeData = '<div style="position:absolute; width:'.$this->size.'px; height:'.$this->size.'px">'; 227 } 228 229 $qrcodeData .= '<div style="font-size:0;position:absolute; width:'.($scale->size * $bcd['num_cols']).'px;height:'.($scale->size * $bcd['num_rows']).'px; top:'.$scale->posY.'px; left:'.$scale->posX.'px" z-index:1;>'."\n"; 230 231 $w = $scale->size; 232 $h = $scale->size; 233 234 // print bars 235 $y = 0; 236 // for each row 237 for ($r = 0; $r < $bcd['num_rows']; ++$r) { 238 $x = 0; 239 // for each column 240 for ($c = 0; $c < $bcd['num_cols']; ++$c) { 241 if ($bcd['bcode'][$r][$c] == 1) { 242 // draw a single barcode cell 243 $qrcodeData .= '<div style="background-color:'.$color.';width:'.$w.'px;height:'.$h.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;"> </div>'."\n"; 244 } 245 $x += $w; 246 } 247 $y += $h; 248 } 249 250 $qrcodeData .= '</div>'."\n"; 251 252 if ($this->emblem != null) { 253 $emblem = $this->emblem; 254 $qrcodeData .= '<div style="position:absolute; z-index:2; width:'.$emblem->area.'px; height:'.$emblem->area.'px; background-image:url('.$emblem->image.'); background-size: cover; background-repeat:no-repeat; background-position: center center; top:'.$emblem->posY.'px; left:'.$emblem->posX.'px"></div>'."\n"; 255 } 256 257 $qrcodeData .= '</div>'."\n"; 258 259 return $qrcodeData; 260 } 261 262 public function getQRcodePngData() 263 { 264 $bcd = $this->barcode->getBarcodeArray(); 265 $this->_borderPx = 0; 266 $color = $this->rgbColor; 267 $scale = $this->scale; 268 269 $w = $bcd['num_cols'] * $scale->size; 270 $h = $bcd['num_rows'] * $scale->size; 271 272 if (function_exists('imagecreate')) { 273 $png = imagecreate($w, $h); 274 $bgcol = imagecolorallocate($png, 255, 255, 255); 275 imagecolortransparent($png, $bgcol); 276 $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); 277 } else { 278 return false; 279 } 280 281 // print bars 282 $y = 0; 283 // for each row 284 for ($r = 0; $r < $bcd['num_rows']; ++$r) { 285 $x = 0; 286 // for each column 287 for ($c = 0; $c < $bcd['num_cols']; ++$c) { 288 if ($bcd['bcode'][$r][$c] == 1) { 289 imagefilledrectangle($png, $x, $y, ($x + $scale->size - 1), ($y + $scale->size - 1), $fgcol); 290 } 291 $x += $scale->size; 292 } 293 $y += $scale->size; 294 } 295 296 $frame = imagecreatetruecolor($this->size, $this->size); 297 $blank = imagecreate($this->size, $this->size); 298 imagecolorallocate($blank, 255, 255, 255); 299 imagecopyresampled($frame, $blank, 0, 0, 0, 0, imagesx($blank), imagesy($blank), imagesx($blank), imagesy($blank)); 300 imagedestroy($blank); 301 imagecopyresampled($frame, $png, $scale->posX, $scale->posY, 0, 0, imagesx($png), imagesy($png), imagesx($png), imagesy($png)); 302 imagedestroy($png); 303 304 if ($this->emblem != null) { 305 $emblem = $this->emblem; 306 $emblemData = file_get_contents($emblem->image); 307 $emblemImage = imagecreatefromstring($emblemData); 308 imagecopyresampled($frame, $emblemImage, ((imagesx($frame) - $emblem->area) / 2), ((imagesy($frame) - $emblem->area) / 2), 0, 0, $emblem->area, $emblem->area, imagesx($emblemImage), imagesy($emblemImage)); 309 imagedestroy($emblemImage); 310 } 311 312 if ($this->file === null) { 313 ob_start(); 314 imagepng($frame); 315 $qrcodeData = ob_get_clean(); 316 } else { 317 preg_match("/\.png$/", $this->file, $output); 318 if (count($output) == 0) 319 throw new \Exception('Incorrect file extension format.'); 320 321 $filePath = explode(DIRECTORY_SEPARATOR, $this->file); 322 if (count($filePath) == 1 ) { 323 $savePath = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR.$this->file; 324 } else { 325 $savePath = $this->file; 326 } 327 328 if (!@imagepng($frame, $savePath)) 329 throw new \Exception('Not found save path.'); 330 331 $qrcodeData = file_get_contents($savePath); 332 } 333 334 imagedestroy($frame); 335 336 return $qrcodeData; 337 } 338 339 public function getQRcodeSvgData() 340 { 341 $bcd = $this->barcode->getBarcodeArray(); 342 $color = $this->hexColor; 343 $scale = $this->scale; 344 345 $w = $bcd['num_cols'] * $scale->size; 346 $h = $bcd['num_rows'] * $scale->size; 347 348 $repstr = array("\0" => '', '&' => '&', '<' => '<', '>' => '>'); 349 $qrcodeData = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n"; 350 $qrcodeData .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n"; 351 $qrcodeData .= '<svg width="'.$this->size.'" height="'.$this->size.'" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'."\n"; 352 $qrcodeData .= "\t".'<desc>'.strtr($bcd['code'], $repstr).'</desc>'."\n"; 353 354 if ($this->margin > 0) { 355 $qrcodeData .= "\t".'<g id="border" fill="none" stroke="'.$color.'">'."\n"; 356 $qrcodeData .= "\t\t".'<rect height="'.$this->size.'" width="'.$this->size.'" y="0" x="0" />'."\n"; 357 $qrcodeData .= "\t".'</g>'."\n"; 358 } 359 360 $qrcodeData .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n"; 361 // print bars 362 $y = $scale->posY; 363 // for each row 364 for ($r = 0; $r < $bcd['num_rows']; ++$r) { 365 $x = $scale->posX; 366 // for each column 367 for ($c = 0; $c < $bcd['num_cols']; ++$c) { 368 if ($bcd['bcode'][$r][$c] == 1) { 369 // draw a single barcode cell 370 $qrcodeData .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$scale->size.'" height="'.$scale->size.'" />'."\n"; 371 } 372 $x += $scale->size; 373 } 374 $y += $scale->size; 375 } 376 $qrcodeData .= "\t".'</g>'."\n"; 377 378 if ($this->emblem != null) { 379 $emblem = $this->emblem; 380 $qrcodeData .= "\t".'<g id="emblem">'."\n"; 381 $qrcodeData .= "\t\t".'<image xlink:href="'.$emblem->image.'" x="'.$emblem->posX.'" y="'.$emblem->posY.'" height="'.$emblem->area.'" width="'.$emblem->area.'"/>'."\n"; 382 $qrcodeData .= "\t".'</g>'."\n"; 383 } 384 385 $qrcodeData .= '</svg>'."\n"; 386 387 if ($this->file != null) { 388 preg_match("/\.svg$/", $this->file, $output); 389 if (count($output) == 0) 390 throw new \Exception('Incorrect file extension format.'); 391 392 $filePath = explode(DIRECTORY_SEPARATOR, $this->file); 393 if (count($filePath) == 1 ) { 394 $savePath = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR.$this->file; 395 } else { 396 $savePath = $this->file; 397 } 398 399 if (!@file_put_contents($savePath, $qrcodeData)) 400 throw new \Exception('Not found save path.'); 401 } 402 403 return $qrcodeData; 404 } 405 406 public function renderHTML() 407 { 408 $qrcodeData = $this->getQRcodeHtmlData(); 409 410 header('Content-Type: text/html'); 411 header('Content-Length: '.strlen($qrcodeData)); 412 header('Cache-Control: no-cache'); 413 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); 414 415 echo $qrcodeData; 416 } 417 418 public function renderPNG() 419 { 420 $qrcodeData = $this->getQRcodePngData(); 421 422 header('Content-Type: image/png'); 423 header('Content-Length: '.strlen($qrcodeData)); 424 header('Cache-Control: no-cache'); 425 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); 426 427 echo $qrcodeData; 428 } 429 430 public function renderSVG() 431 { 432 $qrcodeData = $this->getQRcodeSvgData(); 433 434 header('Content-Type: image/svg+xml'); 435 header('Content-Length: '.strlen($qrcodeData)); 436 header('Cache-Control: no-cache'); 437 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); 438 439 echo $qrcodeData; 440 } 441}