ThinkPHP5生成二维码图片与另一张背景图片进行合成
1、PHP方法
1 public function do_qrcode(){ 2 Vendor('Qrcode.phpqrcode'); 3 Vendor('Qrcode.Compress'); 4 $object = new \QRcode(); 5 $recommend = $user['invite']; 6 //二维码跳转地址 7 $url = config('public.qrcode')."?recommend=".$recommend; 8 //需要合成的背景图片地址 9 $bgimg = config('public.host').config('public.static').'/bj.jpg'; 10 $host = config('public.host'); 11 $path = "./public/qrcode/".$recommend.".jpg"; 12 $r_path = "/public/qrcode/".$recommend.".jpg"; 13 if(!file_exists('./public/qrcode/')){ 14 mkdir('./public/qrcode/',0777,true); 15 } 16 $level=3; 17 $size=5; 18 $errorCorrectionLevel =intval($level) ; 19 $matrixPointSize = intval($size); 20 $object->png($url, $path, $errorCorrectionLevel, $matrixPointSize, 2); 21 //生成的二维码图片地址 22 $img = $host.'/'.$r_path; 23 /* 图片合成开始 */ 24 $bigImg = imagecreatefromstring(file_get_contents($bgimg)); 25 $qCodeImg = imagecreatefromstring(file_get_contents($img)); 26 list($qCodeWidth, $qCodeHight, $qCodeType) = getimagesize($img); 27 imagecopymerge($bigImg, $qCodeImg, 260, 780, 0, 0, $qCodeWidth, $qCodeHight, 100); 28 list($bigWidth, $bigHight, $bigType) = getimagesize($bgimg); 29 imagejpeg($bigImg,"./public/qrcode/".$recommend.".jpg"); 30 /* 图片合成结束 */ 31 $source = "./public/qrcode/".$recommend.".jpg"; 32 $dst_img = "./public/qrcode/".$recommend.".jpg"; 33 $percent = 0.5; #原图压缩,不缩放 34 $image = (new \Compress($source,$percent))->compressImg($dst_img); 35 //合成后的图片地址 36 $img = $host."/public/qrcode/".$recommend.".jpg"; 37 $json = [ 38 'code' => config('code.success'), 39 'msg' => '获取成功', 40 'res' => 'success', 41 'img' => $img 42 ]; 43 echo json_encode($json); 44 exit; 45 }
2、Compress.php
1 <?php 2 class Compress 3 { 4 private $src; 5 private $image; 6 private $imageinfo; 7 private $percent=0.5; 8 9 /* 10 param $src源图 11 param $percent压缩比例 12 */ 13 public function __construct($src,$percent=1) 14 { 15 $this->src = $src; 16 $this->percent = $percent; 17 } 18 19 /* 20 param string $saveName 图片名(可不带扩展名用原图名)用于保存。或不提供文件名直接显示 21 */ 22 public function compressImg($saveName='') 23 { 24 $this->_openImage(); 25 if(!empty($saveName)) 26 { 27 $this->_saveImage($saveName);//保存 28 } 29 else 30 { 31 $this->_showImage(); 32 } 33 } 34 35 /* 36 内部:打开图片 37 */ 38 private function _openImage() 39 { 40 list($width, $height, $type, $attr) = getimagesize($this->src); 41 $this->imageinfo = array( 42 'width'=>$width, 43 'height'=>$height, 44 'type'=>image_type_to_extension($type,false), 45 'attr'=>$attr 46 ); 47 $fun = "imagecreatefrom".$this->imageinfo['type']; 48 $this->image = $fun($this->src); 49 $this->_thumpImage(); 50 } 51 52 /** 53 * 内部:操作图片 54 */ 55 private function _thumpImage() 56 { 57 $new_width = $this->imageinfo['width'] * $this->percent; 58 $new_height = $this->imageinfo['height'] * $this->percent; 59 $image_thump = imagecreatetruecolor($new_width,$new_height); 60 //将原图复制带图片载体上面,并且按照一定比例压缩,极大的保持了清晰度 61 imagecopyresampled($image_thump,$this->image,0,0,0,0,$new_width,$new_height,$this->imageinfo['width'],$this->imageinfo['height']); 62 imagedestroy($this->image); 63 $this->image = $image_thump; 64 } 65 66 /** 67 * 输出图片:保存图片则用saveImage() 68 */ 69 private function _showImage() 70 { 71 header('Content-Type: image/'.$this->imageinfo['type']); 72 $funcs = "image".$this->imageinfo['type']; 73 $funcs($this->image); 74 } 75 76 /** 77 * 保存图片到硬盘: 78 * @param string $dstImgName 1、可指定字符串不带后缀的名称,使用源图扩展名 。2、直接指定目标图片名带扩展名。 79 */ 80 private function _saveImage($dstImgName) 81 { 82 if(empty($dstImgName)) return false; 83 $allowImgs = ['.jpg', '.jpeg', '.png', '.bmp', '.wbmp','.gif']; //如果目标图片名有后缀就用目标图片扩展名 后缀,如果没有,则用源图的扩展名 84 $dstExt = strrchr($dstImgName ,"."); 85 $sourseExt = strrchr($this->src ,"."); 86 if(!empty($dstExt)) $dstExt =strtolower($dstExt); 87 if(!empty($sourseExt)) $sourseExt =strtolower($sourseExt); 88 89 //有指定目标名扩展名 90 if(!empty($dstExt) && in_array($dstExt,$allowImgs)) 91 { 92 $dstName = $dstImgName; 93 } 94 elseif(!empty($sourseExt) && in_array($sourseExt,$allowImgs)) 95 { 96 $dstName = $dstImgName.$sourseExt; 97 } 98 else 99 { 100 $dstName = $dstImgName.$this->imageinfo['type']; 101 } 102 $funcs = "image".$this->imageinfo['type']; 103 $funcs($this->image,$dstName); 104 } 105 106 /** 107 * 销毁图片 108 */ 109 public function __destruct() 110 { 111 imagedestroy($this->image); 112 } 113 }
3、phpqrcode.php
1 <?php 2 3 /* 4 * PHP QR Code encoder 5 * 6 * This file contains MERGED version of PHP QR Code library. 7 * It was auto-generated from full version for your convenience. 8 * 9 * This merged version was configured to not requre any external files, 10 * with disabled cache, error loging and weker but faster mask matching. 11 * If you need tune it up please use non-merged version. 12 * 13 * For full version, documentation, examples of use please visit: 14 * 15 * http://phpqrcode.sourceforge.net/ 16 * https://sourceforge.net/projects/phpqrcode/ 17 * 18 * PHP QR Code is distributed under LGPL 3 19 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 20 * 21 * This library is free software; you can redistribute it and/or 22 * modify it under the terms of the GNU Lesser General Public 23 * License as published by the Free Software Foundation; either 24 * version 3 of the License, or any later version. 25 * 26 * This library is distributed in the hope that it will be useful, 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 29 * Lesser General Public License for more details. 30 * 31 * You should have received a copy of the GNU Lesser General Public 32 * License along with this library; if not, write to the Free Software 33 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 34 */ 35 36 37 38 /* 39 * Version: 1.1.4 40 * Build: 2010100721 41 */ 42 43 44 45 //---- qrconst.php ----------------------------- 46 47 48 49 50 51 /* 52 * PHP QR Code encoder 53 * 54 * Common constants 55 * 56 * Based on libqrencode C library distributed under LGPL 2.1 57 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 58 * 59 * PHP QR Code is distributed under LGPL 3 60 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 61 * 62 * This library is free software; you can redistribute it and/or 63 * modify it under the terms of the GNU Lesser General Public 64 * License as published by the Free Software Foundation; either 65 * version 3 of the License, or any later version. 66 * 67 * This library is distributed in the hope that it will be useful, 68 * but WITHOUT ANY WARRANTY; without even the implied warranty of 69 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 70 * Lesser General Public License for more details. 71 * 72 * You should have received a copy of the GNU Lesser General Public 73 * License along with this library; if not, write to the Free Software 74 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 75 */ 76 77 // Encoding modes 78 79 define('QR_MODE_NUL', -1); 80 define('QR_MODE_NUM', 0); 81 define('QR_MODE_AN', 1); 82 define('QR_MODE_8', 2); 83 define('QR_MODE_KANJI', 3); 84 define('QR_MODE_STRUCTURE', 4); 85 86 // Levels of error correction. 87 88 define('QR_ECLEVEL_L', 0); 89 define('QR_ECLEVEL_M', 1); 90 define('QR_ECLEVEL_Q', 2); 91 define('QR_ECLEVEL_H', 3); 92 93 // Supported output formats 94 95 define('QR_FORMAT_TEXT', 0); 96 define('QR_FORMAT_PNG', 1); 97 98 class qrstr { 99 public static function set(&$srctab, $x, $y, $repl, $replLen = false) { 100 $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl)); 101 } 102 } 103 104 105 106 //---- merged_config.php ----------------------------- 107 108 109 110 111 /* 112 * PHP QR Code encoder 113 * 114 * Config file, tuned-up for merged verion 115 */ 116 117 define('QR_CACHEABLE', false); // use cache - more disk reads but less CPU power, masks and format templates are stored there 118 define('QR_CACHE_DIR', false); // used when QR_CACHEABLE === true 119 define('QR_LOG_DIR', false); // default error logs dir 120 121 define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code 122 define('QR_FIND_FROM_RANDOM', 2); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly 123 define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false 124 125 define('QR_PNG_MAXIMUM_SIZE', 1024); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images 126 127 128 129 130 //---- qrtools.php ----------------------------- 131 132 133 134 135 /* 136 * PHP QR Code encoder 137 * 138 * Toolset, handy and debug utilites. 139 * 140 * PHP QR Code is distributed under LGPL 3 141 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 142 * 143 * This library is free software; you can redistribute it and/or 144 * modify it under the terms of the GNU Lesser General Public 145 * License as published by the Free Software Foundation; either 146 * version 3 of the License, or any later version. 147 * 148 * This library is distributed in the hope that it will be useful, 149 * but WITHOUT ANY WARRANTY; without even the implied warranty of 150 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 151 * Lesser General Public License for more details. 152 * 153 * You should have received a copy of the GNU Lesser General Public 154 * License along with this library; if not, write to the Free Software 155 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 156 */ 157 158 class QRtools { 159 160 //---------------------------------------------------------------------- 161 public static function binarize($frame) 162 { 163 $len = count($frame); 164 foreach ($frame as &$frameLine) { 165 166 for($i=0; $i<$len; $i++) { 167 $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0'; 168 } 169 } 170 171 return $frame; 172 } 173 174 //---------------------------------------------------------------------- 175 public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037') 176 { 177 $barcode_array = array(); 178 179 if (!is_array($mode)) 180 $mode = explode(',', $mode); 181 182 $eccLevel = 'L'; 183 184 if (count($mode) > 1) { 185 $eccLevel = $mode[1]; 186 } 187 188 $qrTab = QRcode::text($code, false, $eccLevel); 189 $size = count($qrTab); 190 191 $barcode_array['num_rows'] = $size; 192 $barcode_array['num_cols'] = $size; 193 $barcode_array['bcode'] = array(); 194 195 foreach ($qrTab as $line) { 196 $arrAdd = array(); 197 foreach(str_split($line) as $char) 198 $arrAdd[] = ($char=='1')?1:0; 199 $barcode_array['bcode'][] = $arrAdd; 200 } 201 202 return $barcode_array; 203 } 204 205 //---------------------------------------------------------------------- 206 public static function clearCache() 207 { 208 self::$frames = array(); 209 } 210 211 //---------------------------------------------------------------------- 212 public static function buildCache() 213 { 214 QRtools::markTime('before_build_cache'); 215 216 $mask = new QRmask(); 217 for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) { 218 $frame = QRspec::newFrame($a); 219 if (QR_IMAGE) { 220 $fileName = QR_CACHE_DIR.'frame_'.$a.'.png'; 221 QRimage::png(self::binarize($frame), $fileName, 1, 0); 222 } 223 224 $width = count($frame); 225 $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); 226 for ($maskNo=0; $maskNo<8; $maskNo++) 227 $mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true); 228 } 229 230 QRtools::markTime('after_build_cache'); 231 } 232 233 //---------------------------------------------------------------------- 234 public static function log($outfile, $err) 235 { 236 if (QR_LOG_DIR !== false) { 237 if ($err != '') { 238 if ($outfile !== false) { 239 file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND); 240 } else { 241 file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND); 242 } 243 } 244 } 245 } 246 247 //---------------------------------------------------------------------- 248 public static function dumpMask($frame) 249 { 250 $width = count($frame); 251 for($y=0;$y<$width;$y++) { 252 for($x=0;$x<$width;$x++) { 253 echo ord($frame[$y][$x]).','; 254 } 255 } 256 } 257 258 //---------------------------------------------------------------------- 259 public static function markTime($markerId) 260 { 261 list($usec, $sec) = explode(" ", microtime()); 262 $time = ((float)$usec + (float)$sec); 263 264 if (!isset($GLOBALS['qr_time_bench'])) 265 $GLOBALS['qr_time_bench'] = array(); 266 267 $GLOBALS['qr_time_bench'][$markerId] = $time; 268 } 269 270 //---------------------------------------------------------------------- 271 public static function timeBenchmark() 272 { 273 self::markTime('finish'); 274 275 $lastTime = 0; 276 $startTime = 0; 277 $p = 0; 278 279 echo '<table cellpadding="3" cellspacing="1"> 280 <thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead> 281 <tbody>'; 282 283 foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) { 284 if ($p > 0) { 285 echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>'; 286 } else { 287 $startTime = $thisTime; 288 } 289 290 $p++; 291 $lastTime = $thisTime; 292 } 293 294 echo '</tbody><tfoot> 295 <tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr> 296 </tfoot> 297 </table>'; 298 } 299 300 } 301 302 //########################################################################## 303 304 QRtools::markTime('start'); 305 306 307 308 309 //---- qrspec.php ----------------------------- 310 311 312 313 314 /* 315 * PHP QR Code encoder 316 * 317 * QR Code specifications 318 * 319 * Based on libqrencode C library distributed under LGPL 2.1 320 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 321 * 322 * PHP QR Code is distributed under LGPL 3 323 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 324 * 325 * The following data / specifications are taken from 326 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) 327 * or 328 * "Automatic identification and data capture techniques -- 329 * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) 330 * 331 * This library is free software; you can redistribute it and/or 332 * modify it under the terms of the GNU Lesser General Public 333 * License as published by the Free Software Foundation; either 334 * version 3 of the License, or any later version. 335 * 336 * This library is distributed in the hope that it will be useful, 337 * but WITHOUT ANY WARRANTY; without even the implied warranty of 338 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 339 * Lesser General Public License for more details. 340 * 341 * You should have received a copy of the GNU Lesser General Public 342 * License along with this library; if not, write to the Free Software 343 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 344 */ 345 346 define('QRSPEC_VERSION_MAX', 40); 347 define('QRSPEC_WIDTH_MAX', 177); 348 349 define('QRCAP_WIDTH', 0); 350 define('QRCAP_WORDS', 1); 351 define('QRCAP_REMINDER', 2); 352 define('QRCAP_EC', 3); 353 354 class QRspec { 355 356 public static $capacity = array( 357 array( 0, 0, 0, array( 0, 0, 0, 0)), 358 array( 21, 26, 0, array( 7, 10, 13, 17)), // 1 359 array( 25, 44, 7, array( 10, 16, 22, 28)), 360 array( 29, 70, 7, array( 15, 26, 36, 44)), 361 array( 33, 100, 7, array( 20, 36, 52, 64)), 362 array( 37, 134, 7, array( 26, 48, 72, 88)), // 5 363 array( 41, 172, 7, array( 36, 64, 96, 112)), 364 array( 45, 196, 0, array( 40, 72, 108, 130)), 365 array( 49, 242, 0, array( 48, 88, 132, 156)), 366 array( 53, 292, 0, array( 60, 110, 160, 192)), 367 array( 57, 346, 0, array( 72, 130, 192, 224)), //10 368 array( 61, 404, 0, array( 80, 150, 224, 264)), 369 array( 65, 466, 0, array( 96, 176, 260, 308)), 370 array( 69, 532, 0, array( 104, 198, 288, 352)), 371 array( 73, 581, 3, array( 120, 216, 320, 384)), 372 array( 77, 655, 3, array( 132, 240, 360, 432)), //15 373 array( 81, 733, 3, array( 144, 280, 408, 480)), 374 array( 85, 815, 3, array( 168, 308, 448, 532)), 375 array( 89, 901, 3, array( 180, 338, 504, 588)), 376 array( 93, 991, 3, array( 196, 364, 546, 650)), 377 array( 97, 1085, 3, array( 224, 416, 600, 700)), //20 378 array(101, 1156, 4, array( 224, 442, 644, 750)), 379 array(105, 1258, 4, array( 252, 476, 690, 816)), 380 array(109, 1364, 4, array( 270, 504, 750, 900)), 381 array(113, 1474, 4, array( 300, 560, 810, 960)), 382 array(117, 1588, 4, array( 312, 588, 870, 1050)), //25 383 array(121, 1706, 4, array( 336, 644, 952, 1110)), 384 array(125, 1828, 4, array( 360, 700, 1020, 1200)), 385 array(129, 1921, 3, array( 390, 728, 1050, 1260)), 386 array(133, 2051, 3, array( 420, 784, 1140, 1350)), 387 array(137, 2185, 3, array( 450, 812, 1200, 1440)), //30 388 array(141, 2323, 3, array( 480, 868, 1290, 1530)), 389 array(145, 2465, 3, array( 510, 924, 1350, 1620)), 390 array(149, 2611, 3, array( 540, 980, 1440, 1710)), 391 array(153, 2761, 3, array( 570, 1036, 1530, 1800)), 392 array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35 393 array(161, 3034, 0, array( 600, 1120, 1680, 1980)), 394 array(165, 3196, 0, array( 630, 1204, 1770, 2100)), 395 array(169, 3362, 0, array( 660, 1260, 1860, 2220)), 396 array(173, 3532, 0, array( 720, 1316, 1950, 2310)), 397 array(177, 3706, 0, array( 750, 1372, 2040, 2430)) //40 398 ); 399 400 //---------------------------------------------------------------------- 401 public static function getDataLength($version, $level) 402 { 403 return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level]; 404 } 405 406 //---------------------------------------------------------------------- 407 public static function getECCLength($version, $level) 408 { 409 return self::$capacity[$version][QRCAP_EC][$level]; 410 } 411 412 //---------------------------------------------------------------------- 413 public static function getWidth($version) 414 { 415 return self::$capacity[$version][QRCAP_WIDTH]; 416 } 417 418 //---------------------------------------------------------------------- 419 public static function getRemainder($version) 420 { 421 return self::$capacity[$version][QRCAP_REMINDER]; 422 } 423 424 //---------------------------------------------------------------------- 425 public static function getMinimumVersion($size, $level) 426 { 427 428 for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) { 429 $words = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level]; 430 if($words >= $size) 431 return $i; 432 } 433 434 return -1; 435 } 436 437 //###################################################################### 438 439 public static $lengthTableBits = array( 440 array(10, 12, 14), 441 array( 9, 11, 13), 442 array( 8, 16, 16), 443 array( 8, 10, 12) 444 ); 445 446 //---------------------------------------------------------------------- 447 public static function lengthIndicator($mode, $version) 448 { 449 if ($mode == QR_MODE_STRUCTURE) 450 return 0; 451 452 if ($version <= 9) { 453 $l = 0; 454 } else if ($version <= 26) { 455 $l = 1; 456 } else { 457 $l = 2; 458 } 459 460 return self::$lengthTableBits[$mode][$l]; 461 } 462 463 //---------------------------------------------------------------------- 464 public static function maximumWords($mode, $version) 465 { 466 if($mode == QR_MODE_STRUCTURE) 467 return 3; 468 469 if($version <= 9) { 470 $l = 0; 471 } else if($version <= 26) { 472 $l = 1; 473 } else { 474 $l = 2; 475 } 476 477 $bits = self::$lengthTableBits[$mode][$l]; 478 $words = (1 << $bits) - 1; 479 480 if($mode == QR_MODE_KANJI) { 481 $words *= 2; // the number of bytes is required 482 } 483 484 return $words; 485 } 486 487 // Error correction code ----------------------------------------------- 488 // Table of the error correction code (Reed-Solomon block) 489 // See Table 12-16 (pp.30-36), JIS X0510:2004. 490 491 public static $eccTable = array( 492 array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), 493 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1 494 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), 495 array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)), 496 array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)), 497 array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5 498 array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)), 499 array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)), 500 array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)), 501 array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)), 502 array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), //10 503 array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)), 504 array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)), 505 array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)), 506 array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)), 507 array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), //15 508 array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)), 509 array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)), 510 array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)), 511 array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)), 512 array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), //20 513 array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)), 514 array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)), 515 array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)), 516 array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)), 517 array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), //25 518 array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), 519 array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)), 520 array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), 521 array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)), 522 array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30 523 array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)), 524 array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), 525 array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), 526 array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), 527 array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), //35 528 array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), 529 array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), 530 array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), 531 array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), 532 array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)),//40 533 ); 534 535 //---------------------------------------------------------------------- 536 // CACHEABLE!!! 537 538 public static function getEccSpec($version, $level, array &$spec) 539 { 540 if (count($spec) < 5) { 541 $spec = array(0,0,0,0,0); 542 } 543 544 $b1 = self::$eccTable[$version][$level][0]; 545 $b2 = self::$eccTable[$version][$level][1]; 546 $data = self::getDataLength($version, $level); 547 $ecc = self::getECCLength($version, $level); 548 549 if($b2 == 0) { 550 $spec[0] = $b1; 551 $spec[1] = (int)($data / $b1); 552 $spec[2] = (int)($ecc / $b1); 553 $spec[3] = 0; 554 $spec[4] = 0; 555 } else { 556 $spec[0] = $b1; 557 $spec[1] = (int)($data / ($b1 + $b2)); 558 $spec[2] = (int)($ecc / ($b1 + $b2)); 559 $spec[3] = $b2; 560 $spec[4] = $spec[1] + 1; 561 } 562 } 563 564 // Alignment pattern --------------------------------------------------- 565 566 // Positions of alignment patterns. 567 // This array includes only the second and the third position of the 568 // alignment patterns. Rest of them can be calculated from the distance 569 // between them. 570 571 // See Table 1 in Appendix E (pp.71) of JIS X0510:2004. 572 573 public static $alignmentPattern = array( 574 array( 0, 0), 575 array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5 576 array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10 577 array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15 578 array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20 579 array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25 580 array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30 581 array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35 582 array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40 583 ); 584 585 586 /** -------------------------------------------------------------------- 587 * Put an alignment marker. 588 * @param frame 589 * @param width 590 * @param ox,oy center coordinate of the pattern 591 */ 592 public static function putAlignmentMarker(array &$frame, $ox, $oy) 593 { 594 $finder = array( 595 "\xa1\xa1\xa1\xa1\xa1", 596 "\xa1\xa0\xa0\xa0\xa1", 597 "\xa1\xa0\xa1\xa0\xa1", 598 "\xa1\xa0\xa0\xa0\xa1", 599 "\xa1\xa1\xa1\xa1\xa1" 600 ); 601 602 $yStart = $oy-2; 603 $xStart = $ox-2; 604 605 for($y=0; $y<5; $y++) { 606 QRstr::set($frame, $xStart, $yStart+$y, $finder[$y]); 607 } 608 } 609 610 //---------------------------------------------------------------------- 611 public static function putAlignmentPattern($version, &$frame, $width) 612 { 613 if($version < 2) 614 return; 615 616 $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0]; 617 if($d < 0) { 618 $w = 2; 619 } else { 620 $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2); 621 } 622 623 if($w * $w - 3 == 1) { 624 $x = self::$alignmentPattern[$version][0]; 625 $y = self::$alignmentPattern[$version][0]; 626 self::putAlignmentMarker($frame, $x, $y); 627 return; 628 } 629 630 $cx = self::$alignmentPattern[$version][0]; 631 for($x=1; $x<$w - 1; $x++) { 632 self::putAlignmentMarker($frame, 6, $cx); 633 self::putAlignmentMarker($frame, $cx, 6); 634 $cx += $d; 635 } 636 637 $cy = self::$alignmentPattern[$version][0]; 638 for($y=0; $y<$w-1; $y++) { 639 $cx = self::$alignmentPattern[$version][0]; 640 for($x=0; $x<$w-1; $x++) { 641 self::putAlignmentMarker($frame, $cx, $cy); 642 $cx += $d; 643 } 644 $cy += $d; 645 } 646 } 647 648 // Version information pattern ----------------------------------------- 649 650 // Version information pattern (BCH coded). 651 // See Table 1 in Appendix D (pp.68) of JIS X0510:2004. 652 653 // size: [QRSPEC_VERSION_MAX - 6] 654 655 public static $versionPattern = array( 656 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 657 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 658 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, 659 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 660 0x27541, 0x28c69 661 ); 662 663 //---------------------------------------------------------------------- 664 public static function getVersionPattern($version) 665 { 666 if($version < 7 || $version > QRSPEC_VERSION_MAX) 667 return 0; 668 669 return self::$versionPattern[$version -7]; 670 } 671 672 // Format information -------------------------------------------------- 673 // See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib) 674 675 public static $formatInfo = array( 676 array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), 677 array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), 678 array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), 679 array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) 680 ); 681 682 public static function getFormatInfo($mask, $level) 683 { 684 if($mask < 0 || $mask > 7) 685 return 0; 686 687 if($level < 0 || $level > 3) 688 return 0; 689 690 return self::$formatInfo[$level][$mask]; 691 } 692 693 // Frame --------------------------------------------------------------- 694 // Cache of initial frames. 695 696 public static $frames = array(); 697 698 /** -------------------------------------------------------------------- 699 * Put a finder pattern. 700 * @param frame 701 * @param width 702 * @param ox,oy upper-left coordinate of the pattern 703 */ 704 public static function putFinderPattern(&$frame, $ox, $oy) 705 { 706 $finder = array( 707 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1", 708 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", 709 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", 710 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", 711 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", 712 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", 713 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1" 714 ); 715 716 for($y=0; $y<7; $y++) { 717 QRstr::set($frame, $ox, $oy+$y, $finder[$y]); 718 } 719 } 720 721 //---------------------------------------------------------------------- 722 public static function createFrame($version) 723 { 724 $width = self::$capacity[$version][QRCAP_WIDTH]; 725 $frameLine = str_repeat ("\0", $width); 726 $frame = array_fill(0, $width, $frameLine); 727 728 // Finder pattern 729 self::putFinderPattern($frame, 0, 0); 730 self::putFinderPattern($frame, $width - 7, 0); 731 self::putFinderPattern($frame, 0, $width - 7); 732 733 // Separator 734 $yOffset = $width - 7; 735 736 for($y=0; $y<7; $y++) { 737 $frame[$y][7] = "\xc0"; 738 $frame[$y][$width - 8] = "\xc0"; 739 $frame[$yOffset][7] = "\xc0"; 740 $yOffset++; 741 } 742 743 $setPattern = str_repeat("\xc0", 8); 744 745 QRstr::set($frame, 0, 7, $setPattern); 746 QRstr::set($frame, $width-8, 7, $setPattern); 747 QRstr::set($frame, 0, $width - 8, $setPattern); 748 749 // Format info 750 $setPattern = str_repeat("\x84", 9); 751 QRstr::set($frame, 0, 8, $setPattern); 752 QRstr::set($frame, $width - 8, 8, $setPattern, 8); 753 754 $yOffset = $width - 8; 755 756 for($y=0; $y<8; $y++,$yOffset++) { 757 $frame[$y][8] = "\x84"; 758 $frame[$yOffset][8] = "\x84"; 759 } 760 761 // Timing pattern 762 763 for($i=1; $i<$width-15; $i++) { 764 $frame[6][7+$i] = chr(0x90 | ($i & 1)); 765 $frame[7+$i][6] = chr(0x90 | ($i & 1)); 766 } 767 768 // Alignment pattern 769 self::putAlignmentPattern($version, $frame, $width); 770 771 // Version information 772 if($version >= 7) { 773 $vinf = self::getVersionPattern($version); 774 775 $v = $vinf; 776 777 for($x=0; $x<6; $x++) { 778 for($y=0; $y<3; $y++) { 779 $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1)); 780 $v = $v >> 1; 781 } 782 } 783 784 $v = $vinf; 785 for($y=0; $y<6; $y++) { 786 for($x=0; $x<3; $x++) { 787 $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1)); 788 $v = $v >> 1; 789 } 790 } 791 } 792 793 // and a little bit... 794 $frame[$width - 8][8] = "\x81"; 795 796 return $frame; 797 } 798 799 //---------------------------------------------------------------------- 800 public static function debug($frame, $binary_mode = false) 801 { 802 if ($binary_mode) { 803 804 foreach ($frame as &$frameLine) { 805 $frameLine = join('<span class="m"> </span>', explode('0', $frameLine)); 806 $frameLine = join('██', explode('1', $frameLine)); 807 } 808 809 ?> 810 <style> 811 .m { background-color: white; } 812 </style> 813 <?php 814 echo '<pre><tt><br/ ><br/ ><br/ > '; 815 echo join("<br/ > ", $frame); 816 echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >'; 817 818 } else { 819 820 foreach ($frame as &$frameLine) { 821 $frameLine = join('<span class="m"> </span>', explode("\xc0", $frameLine)); 822 $frameLine = join('<span class="m">▒</span>', explode("\xc1", $frameLine)); 823 $frameLine = join('<span class="p"> </span>', explode("\xa0", $frameLine)); 824 $frameLine = join('<span class="p">▒</span>', explode("\xa1", $frameLine)); 825 $frameLine = join('<span class="s">◇</span>', explode("\x84", $frameLine)); //format 0 826 $frameLine = join('<span class="s">◆</span>', explode("\x85", $frameLine)); //format 1 827 $frameLine = join('<span class="x">☢</span>', explode("\x81", $frameLine)); //special bit 828 $frameLine = join('<span class="c"> </span>', explode("\x90", $frameLine)); //clock 0 829 $frameLine = join('<span class="c">◷</span>', explode("\x91", $frameLine)); //clock 1 830 $frameLine = join('<span class="f"> </span>', explode("\x88", $frameLine)); //version 831 $frameLine = join('<span class="f">▒</span>', explode("\x89", $frameLine)); //version 832 $frameLine = join('♦', explode("\x01", $frameLine)); 833 $frameLine = join('⋅', explode("\0", $frameLine)); 834 } 835 836 ?> 837 <style> 838 .p { background-color: yellow; } 839 .m { background-color: #00FF00; } 840 .s { background-color: #FF0000; } 841 .c { background-color: aqua; } 842 .x { background-color: pink; } 843 .f { background-color: gold; } 844 </style> 845 <?php 846 echo "<pre><tt>"; 847 echo join("<br/ >", $frame); 848 echo "</tt></pre>"; 849 850 } 851 } 852 853 //---------------------------------------------------------------------- 854 public static function serial($frame) 855 { 856 return gzcompress(join("\n", $frame), 9); 857 } 858 859 //---------------------------------------------------------------------- 860 public static function unserial($code) 861 { 862 return explode("\n", gzuncompress($code)); 863 } 864 865 //---------------------------------------------------------------------- 866 public static function newFrame($version) 867 { 868 if($version < 1 || $version > QRSPEC_VERSION_MAX) 869 return null; 870 871 if(!isset(self::$frames[$version])) { 872 873 $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat'; 874 875 if (QR_CACHEABLE) { 876 if (file_exists($fileName)) { 877 self::$frames[$version] = self::unserial(file_get_contents($fileName)); 878 } else { 879 self::$frames[$version] = self::createFrame($version); 880 file_put_contents($fileName, self::serial(self::$frames[$version])); 881 } 882 } else { 883 self::$frames[$version] = self::createFrame($version); 884 } 885 } 886 887 if(is_null(self::$frames[$version])) 888 return null; 889 890 return self::$frames[$version]; 891 } 892 893 //---------------------------------------------------------------------- 894 public static function rsBlockNum($spec) { return $spec[0] + $spec[3]; } 895 public static function rsBlockNum1($spec) { return $spec[0]; } 896 public static function rsDataCodes1($spec) { return $spec[1]; } 897 public static function rsEccCodes1($spec) { return $spec[2]; } 898 public static function rsBlockNum2($spec) { return $spec[3]; } 899 public static function rsDataCodes2($spec) { return $spec[4]; } 900 public static function rsEccCodes2($spec) { return $spec[2]; } 901 public static function rsDataLength($spec) { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); } 902 public static function rsEccLength($spec) { return ($spec[0] + $spec[3]) * $spec[2]; } 903 904 } 905 906 907 908 //---- qrimage.php ----------------------------- 909 910 911 912 913 /* 914 * PHP QR Code encoder 915 * 916 * Image output of code using GD2 917 * 918 * PHP QR Code is distributed under LGPL 3 919 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 920 * 921 * This library is free software; you can redistribute it and/or 922 * modify it under the terms of the GNU Lesser General Public 923 * License as published by the Free Software Foundation; either 924 * version 3 of the License, or any later version. 925 * 926 * This library is distributed in the hope that it will be useful, 927 * but WITHOUT ANY WARRANTY; without even the implied warranty of 928 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 929 * Lesser General Public License for more details. 930 * 931 * You should have received a copy of the GNU Lesser General Public 932 * License along with this library; if not, write to the Free Software 933 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 934 */ 935 936 define('QR_IMAGE', true); 937 938 class QRimage { 939 940 //---------------------------------------------------------------------- 941 public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE) 942 { 943 $image = self::image($frame, $pixelPerPoint, $outerFrame); 944 945 if ($filename === false) { 946 Header("Content-type: image/png"); 947 ImagePng($image); 948 } else { 949 if($saveandprint===TRUE){ 950 ImagePng($image, $filename); 951 header("Content-type: image/png"); 952 ImagePng($image); 953 }else{ 954 ImagePng($image, $filename); 955 } 956 } 957 958 ImageDestroy($image); 959 } 960 961 //---------------------------------------------------------------------- 962 public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85) 963 { 964 $image = self::image($frame, $pixelPerPoint, $outerFrame); 965 966 if ($filename === false) { 967 Header("Content-type: image/jpeg"); 968 ImageJpeg($image, null, $q); 969 } else { 970 ImageJpeg($image, $filename, $q); 971 } 972 973 ImageDestroy($image); 974 } 975 976 //---------------------------------------------------------------------- 977 private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4) 978 { 979 $h = count($frame); 980 $w = strlen($frame[0]); 981 982 $imgW = $w + 2*$outerFrame; 983 $imgH = $h + 2*$outerFrame; 984 985 $base_image =ImageCreate($imgW, $imgH); 986 987 $col[0] = ImageColorAllocate($base_image,255,255,255); 988 $col[1] = ImageColorAllocate($base_image,0,0,0); 989 990 imagefill($base_image, 0, 0, $col[0]); 991 992 for($y=0; $y<$h; $y++) { 993 for($x=0; $x<$w; $x++) { 994 if ($frame[$y][$x] == '1') { 995 ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]); 996 } 997 } 998 } 999 1000 $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint); 1001 ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH); 1002 ImageDestroy($base_image); 1003 1004 return $target_image; 1005 } 1006 } 1007 1008 1009 1010 //---- qrinput.php ----------------------------- 1011 1012 1013 1014 1015 /* 1016 * PHP QR Code encoder 1017 * 1018 * Input encoding class 1019 * 1020 * Based on libqrencode C library distributed under LGPL 2.1 1021 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 1022 * 1023 * PHP QR Code is distributed under LGPL 3 1024 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 1025 * 1026 * This library is free software; you can redistribute it and/or 1027 * modify it under the terms of the GNU Lesser General Public 1028 * License as published by the Free Software Foundation; either 1029 * version 3 of the License, or any later version. 1030 * 1031 * This library is distributed in the hope that it will be useful, 1032 * but WITHOUT ANY WARRANTY; without even the implied warranty of 1033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1034 * Lesser General Public License for more details. 1035 * 1036 * You should have received a copy of the GNU Lesser General Public 1037 * License along with this library; if not, write to the Free Software 1038 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 1039 */ 1040 1041 define('STRUCTURE_HEADER_BITS', 20); 1042 define('MAX_STRUCTURED_SYMBOLS', 16); 1043 1044 class QRinputItem { 1045 1046 public $mode; 1047 public $size; 1048 public $data; 1049 public $bstream; 1050 1051 public function __construct($mode, $size, $data, $bstream = null) 1052 { 1053 $setData = array_slice($data, 0, $size); 1054 1055 if (count($setData) < $size) { 1056 $setData = array_merge($setData, array_fill(0,$size-count($setData),0)); 1057 } 1058 1059 if(!QRinput::check($mode, $size, $setData)) { 1060 throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData)); 1061 return null; 1062 } 1063 1064 $this->mode = $mode; 1065 $this->size = $size; 1066 $this->data = $setData; 1067 $this->bstream = $bstream; 1068 } 1069 1070 //---------------------------------------------------------------------- 1071 public function encodeModeNum($version) 1072 { 1073 try { 1074 1075 $words = (int)($this->size / 3); 1076 $bs = new QRbitstream(); 1077 1078 $val = 0x1; 1079 $bs->appendNum(4, $val); 1080 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size); 1081 1082 for($i=0; $i<$words; $i++) { 1083 $val = (ord($this->data[$i*3 ]) - ord('0')) * 100; 1084 $val += (ord($this->data[$i*3+1]) - ord('0')) * 10; 1085 $val += (ord($this->data[$i*3+2]) - ord('0')); 1086 $bs->appendNum(10, $val); 1087 } 1088 1089 if($this->size - $words * 3 == 1) { 1090 $val = ord($this->data[$words*3]) - ord('0'); 1091 $bs->appendNum(4, $val); 1092 } else if($this->size - $words * 3 == 2) { 1093 $val = (ord($this->data[$words*3 ]) - ord('0')) * 10; 1094 $val += (ord($this->data[$words*3+1]) - ord('0')); 1095 $bs->appendNum(7, $val); 1096 } 1097 1098 $this->bstream = $bs; 1099 return 0; 1100 1101 } catch (Exception $e) { 1102 return -1; 1103 } 1104 } 1105 1106 //---------------------------------------------------------------------- 1107 public function encodeModeAn($version) 1108 { 1109 try { 1110 $words = (int)($this->size / 2); 1111 $bs = new QRbitstream(); 1112 1113 $bs->appendNum(4, 0x02); 1114 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size); 1115 1116 for($i=0; $i<$words; $i++) { 1117 $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45; 1118 $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1])); 1119 1120 $bs->appendNum(11, $val); 1121 } 1122 1123 if($this->size & 1) { 1124 $val = QRinput::lookAnTable(ord($this->data[$words * 2])); 1125 $bs->appendNum(6, $val); 1126 } 1127 1128 $this->bstream = $bs; 1129 return 0; 1130 1131 } catch (Exception $e) { 1132 return -1; 1133 } 1134 } 1135 1136 //---------------------------------------------------------------------- 1137 public function encodeMode8($version) 1138 { 1139 try { 1140 $bs = new QRbitstream(); 1141 1142 $bs->appendNum(4, 0x4); 1143 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size); 1144 1145 for($i=0; $i<$this->size; $i++) { 1146 $bs->appendNum(8, ord($this->data[$i])); 1147 } 1148 1149 $this->bstream = $bs; 1150 return 0; 1151 1152 } catch (Exception $e) { 1153 return -1; 1154 } 1155 } 1156 1157 //---------------------------------------------------------------------- 1158 public function encodeModeKanji($version) 1159 { 1160 try { 1161 1162 $bs = new QRbitrtream(); 1163 1164 $bs->appendNum(4, 0x8); 1165 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2)); 1166 1167 for($i=0; $i<$this->size; $i+=2) { 1168 $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]); 1169 if($val <= 0x9ffc) { 1170 $val -= 0x8140; 1171 } else { 1172 $val -= 0xc140; 1173 } 1174 1175 $h = ($val >> 8) * 0xc0; 1176 $val = ($val & 0xff) + $h; 1177 1178 $bs->appendNum(13, $val); 1179 } 1180 1181 $this->bstream = $bs; 1182 return 0; 1183 1184 } catch (Exception $e) { 1185 return -1; 1186 } 1187 } 1188 1189 //---------------------------------------------------------------------- 1190 public function encodeModeStructure() 1191 { 1192 try { 1193 $bs = new QRbitstream(); 1194 1195 $bs->appendNum(4, 0x03); 1196 $bs->appendNum(4, ord($this->data[1]) - 1); 1197 $bs->appendNum(4, ord($this->data[0]) - 1); 1198 $bs->appendNum(8, ord($this->data[2])); 1199 1200 $this->bstream = $bs; 1201 return 0; 1202 1203 } catch (Exception $e) { 1204 return -1; 1205 } 1206 } 1207 1208 //---------------------------------------------------------------------- 1209 public function estimateBitStreamSizeOfEntry($version) 1210 { 1211 $bits = 0; 1212 1213 if($version == 0) 1214 $version = 1; 1215 1216 switch($this->mode) { 1217 case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break; 1218 case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break; 1219 case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break; 1220 case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break; 1221 case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS; 1222 default: 1223 return 0; 1224 } 1225 1226 $l = QRspec::lengthIndicator($this->mode, $version); 1227 $m = 1 << $l; 1228 $num = (int)(($this->size + $m - 1) / $m); 1229 1230 $bits += $num * (4 + $l); 1231 1232 return $bits; 1233 } 1234 1235 //---------------------------------------------------------------------- 1236 public function encodeBitStream($version) 1237 { 1238 try { 1239 1240 unset($this->bstream); 1241 $words = QRspec::maximumWords($this->mode, $version); 1242 1243 if($this->size > $words) { 1244 1245 $st1 = new QRinputItem($this->mode, $words, $this->data); 1246 $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words)); 1247 1248 $st1->encodeBitStream($version); 1249 $st2->encodeBitStream($version); 1250 1251 $this->bstream = new QRbitstream(); 1252 $this->bstream->append($st1->bstream); 1253 $this->bstream->append($st2->bstream); 1254 1255 unset($st1); 1256 unset($st2); 1257 1258 } else { 1259 1260 $ret = 0; 1261 1262 switch($this->mode) { 1263 case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break; 1264 case QR_MODE_AN: $ret = $this->encodeModeAn($version); break; 1265 case QR_MODE_8: $ret = $this->encodeMode8($version); break; 1266 case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break; 1267 case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break; 1268 1269 default: 1270 break; 1271 } 1272 1273 if($ret < 0) 1274 return -1; 1275 } 1276 1277 return $this->bstream->size(); 1278 1279 } catch (Exception $e) { 1280 return -1; 1281 } 1282 } 1283 }; 1284 1285 //########################################################################## 1286 1287 class QRinput { 1288 1289 public $items; 1290 1291 private $version; 1292 private $level; 1293 1294 //---------------------------------------------------------------------- 1295 public function __construct($version = 0, $level = QR_ECLEVEL_L) 1296 { 1297 if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) { 1298 throw new Exception('Invalid version no'); 1299 return NULL; 1300 } 1301 1302 $this->version = $version; 1303 $this->level = $level; 1304 } 1305 1306 //---------------------------------------------------------------------- 1307 public function getVersion() 1308 { 1309 return $this->version; 1310 } 1311 1312 //---------------------------------------------------------------------- 1313 public function setVersion($version) 1314 { 1315 if($version < 0 || $version > QRSPEC_VERSION_MAX) { 1316 throw new Exception('Invalid version no'); 1317 return -1; 1318 } 1319 1320 $this->version = $version; 1321 1322 return 0; 1323 } 1324 1325 //---------------------------------------------------------------------- 1326 public function getErrorCorrectionLevel() 1327 { 1328 return $this->level; 1329 } 1330 1331 //---------------------------------------------------------------------- 1332 public function setErrorCorrectionLevel($level) 1333 { 1334 if($level > QR_ECLEVEL_H) { 1335 throw new Exception('Invalid ECLEVEL'); 1336 return -1; 1337 } 1338 1339 $this->level = $level; 1340 1341 return 0; 1342 } 1343 1344 //---------------------------------------------------------------------- 1345 public function appendEntry(QRinputItem $entry) 1346 { 1347 $this->items[] = $entry; 1348 } 1349 1350 //---------------------------------------------------------------------- 1351 public function append($mode, $size, $data) 1352 { 1353 try { 1354 $entry = new QRinputItem($mode, $size, $data); 1355 $this->items[] = $entry; 1356 return 0; 1357 } catch (Exception $e) { 1358 return -1; 1359 } 1360 } 1361 1362 //---------------------------------------------------------------------- 1363 1364 public function insertStructuredAppendHeader($size, $index, $parity) 1365 { 1366 if( $size > MAX_STRUCTURED_SYMBOLS ) { 1367 throw new Exception('insertStructuredAppendHeader wrong size'); 1368 } 1369 1370 if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) { 1371 throw new Exception('insertStructuredAppendHeader wrong index'); 1372 } 1373 1374 $buf = array($size, $index, $parity); 1375 1376 try { 1377 $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf); 1378 array_unshift($this->items, $entry); 1379 return 0; 1380 } catch (Exception $e) { 1381 return -1; 1382 } 1383 } 1384 1385 //---------------------------------------------------------------------- 1386 public function calcParity() 1387 { 1388 $parity = 0; 1389 1390 foreach($this->items as $item) { 1391 if($item->mode != QR_MODE_STRUCTURE) { 1392 for($i=$item->size-1; $i>=0; $i--) { 1393 $parity ^= $item->data[$i]; 1394 } 1395 } 1396 } 1397 1398 return $parity; 1399 } 1400 1401 //---------------------------------------------------------------------- 1402 public static function checkModeNum($size, $data) 1403 { 1404 for($i=0; $i<$size; $i++) { 1405 if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){ 1406 return false; 1407 } 1408 } 1409 1410 return true; 1411 } 1412 1413 //---------------------------------------------------------------------- 1414 public static function estimateBitsModeNum($size) 1415 { 1416 $w = (int)$size / 3; 1417 $bits = $w * 10; 1418 1419 switch($size - $w * 3) { 1420 case 1: 1421 $bits += 4; 1422 break; 1423 case 2: 1424 $bits += 7; 1425 break; 1426 default: 1427 break; 1428 } 1429 1430 return $bits; 1431 } 1432 1433 //---------------------------------------------------------------------- 1434 public static $anTable = array( 1435 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1436 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1437 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 1438 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, 1439 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 1440 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, 1441 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1442 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 1443 ); 1444 1445 //---------------------------------------------------------------------- 1446 public static function lookAnTable($c) 1447 { 1448 return (($c > 127)?-1:self::$anTable[$c]); 1449 } 1450 1451 //---------------------------------------------------------------------- 1452 public static function checkModeAn($size, $data) 1453 { 1454 for($i=0; $i<$size; $i++) { 1455 if (self::lookAnTable(ord($data[$i])) == -1) { 1456 return false; 1457 } 1458 } 1459 1460 return true; 1461 } 1462 1463 //---------------------------------------------------------------------- 1464 public static function estimateBitsModeAn($size) 1465 { 1466 $w = (int)($size / 2); 1467 $bits = $w * 11; 1468 1469 if($size & 1) { 1470 $bits += 6; 1471 } 1472 1473 return $bits; 1474 } 1475 1476 //---------------------------------------------------------------------- 1477 public static function estimateBitsMode8($size) 1478 { 1479 return $size * 8; 1480 } 1481 1482 //---------------------------------------------------------------------- 1483 public function estimateBitsModeKanji($size) 1484 { 1485 return (int)(($size / 2) * 13); 1486 } 1487 1488 //---------------------------------------------------------------------- 1489 public static function checkModeKanji($size, $data) 1490 { 1491 if($size & 1) 1492 return false; 1493 1494 for($i=0; $i<$size; $i+=2) { 1495 $val = (ord($data[$i]) << 8) | ord($data[$i+1]); 1496 if( $val < 0x8140 1497 || ($val > 0x9ffc && $val < 0xe040) 1498 || $val > 0xebbf) { 1499 return false; 1500 } 1501 } 1502 1503 return true; 1504 } 1505 1506 /*********************************************************************** 1507 * Validation 1508 **********************************************************************/ 1509 1510 public static function check($mode, $size, $data) 1511 { 1512 if($size <= 0) 1513 return false; 1514 1515 switch($mode) { 1516 case QR_MODE_NUM: return self::checkModeNum($size, $data); break; 1517 case QR_MODE_AN: return self::checkModeAn($size, $data); break; 1518 case QR_MODE_KANJI: return self::checkModeKanji($size, $data); break; 1519 case QR_MODE_8: return true; break; 1520 case QR_MODE_STRUCTURE: return true; break; 1521 1522 default: 1523 break; 1524 } 1525 1526 return false; 1527 } 1528 1529 1530 //---------------------------------------------------------------------- 1531 public function estimateBitStreamSize($version) 1532 { 1533 $bits = 0; 1534 1535 foreach($this->items as $item) { 1536 $bits += $item->estimateBitStreamSizeOfEntry($version); 1537 } 1538 1539 return $bits; 1540 } 1541 1542 //---------------------------------------------------------------------- 1543 public function estimateVersion() 1544 { 1545 $version = 0; 1546 $prev = 0; 1547 do { 1548 $prev = $version; 1549 $bits = $this->estimateBitStreamSize($prev); 1550 $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level); 1551 if ($version < 0) { 1552 return -1; 1553 } 1554 } while ($version > $prev); 1555 1556 return $version; 1557 } 1558 1559 //---------------------------------------------------------------------- 1560 public static function lengthOfCode($mode, $version, $bits) 1561 { 1562 $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version); 1563 switch($mode) { 1564 case QR_MODE_NUM: 1565 $chunks = (int)($payload / 10); 1566 $remain = $payload - $chunks * 10; 1567 $size = $chunks * 3; 1568 if($remain >= 7) { 1569 $size += 2; 1570 } else if($remain >= 4) { 1571 $size += 1; 1572 } 1573 break; 1574 case QR_MODE_AN: 1575 $chunks = (int)($payload / 11); 1576 $remain = $payload - $chunks * 11; 1577 $size = $chunks * 2; 1578 if($remain >= 6) 1579 $size++; 1580 break; 1581 case QR_MODE_8: 1582 $size = (int)($payload / 8); 1583 break; 1584 case QR_MODE_KANJI: 1585 $size = (int)(($payload / 13) * 2); 1586 break; 1587 case QR_MODE_STRUCTURE: 1588 $size = (int)($payload / 8); 1589 break; 1590 default: 1591 $size = 0; 1592 break; 1593 } 1594 1595 $maxsize = QRspec::maximumWords($mode, $version); 1596 if($size < 0) $size = 0; 1597 if($size > $maxsize) $size = $maxsize; 1598 1599 return $size; 1600 } 1601 1602 //---------------------------------------------------------------------- 1603 public function createBitStream() 1604 { 1605 $total = 0; 1606 1607 foreach($this->items as $item) { 1608 $bits = $item->encodeBitStream($this->version); 1609 1610 if($bits < 0) 1611 return -1; 1612 1613 $total += $bits; 1614 } 1615 1616 return $total; 1617 } 1618 1619 //---------------------------------------------------------------------- 1620 public function convertData() 1621 { 1622 $ver = $this->estimateVersion(); 1623 if($ver > $this->getVersion()) { 1624 $this->setVersion($ver); 1625 } 1626 1627 for(;;) { 1628 $bits = $this->createBitStream(); 1629 1630 if($bits < 0) 1631 return -1; 1632 1633 $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level); 1634 if($ver < 0) { 1635 throw new Exception('WRONG VERSION'); 1636 return -1; 1637 } else if($ver > $this->getVersion()) { 1638 $this->setVersion($ver); 1639 } else { 1640 break; 1641 } 1642 } 1643 1644 return 0; 1645 } 1646 1647 //---------------------------------------------------------------------- 1648 public function appendPaddingBit(&$bstream) 1649 { 1650 $bits = $bstream->size(); 1651 $maxwords = QRspec::getDataLength($this->version, $this->level); 1652 $maxbits = $maxwords * 8; 1653 1654 if ($maxbits == $bits) { 1655 return 0; 1656 } 1657 1658 if ($maxbits - $bits < 5) { 1659 return $bstream->appendNum($maxbits - $bits, 0); 1660 } 1661 1662 $bits += 4; 1663 $words = (int)(($bits + 7) / 8); 1664 1665 $padding = new QRbitstream(); 1666 $ret = $padding->appendNum($words * 8 - $bits + 4, 0); 1667 1668 if($ret < 0) 1669 return $ret; 1670 1671 $padlen = $maxwords - $words; 1672 1673 if($padlen > 0) { 1674 1675 $padbuf = array(); 1676 for($i=0; $i<$padlen; $i++) { 1677 $padbuf[$i] = ($i&1)?0x11:0xec; 1678 } 1679 1680 $ret = $padding->appendBytes($padlen, $padbuf); 1681 1682 if($ret < 0) 1683 return $ret; 1684 1685 } 1686 1687 $ret = $bstream->append($padding); 1688 1689 return $ret; 1690 } 1691 1692 //---------------------------------------------------------------------- 1693 public function mergeBitStream() 1694 { 1695 if($this->convertData() < 0) { 1696 return null; 1697 } 1698 1699 $bstream = new QRbitstream(); 1700 1701 foreach($this->items as $item) { 1702 $ret = $bstream->append($item->bstream); 1703 if($ret < 0) { 1704 return null; 1705 } 1706 } 1707 1708 return $bstream; 1709 } 1710 1711 //---------------------------------------------------------------------- 1712 public function getBitStream() 1713 { 1714 1715 $bstream = $this->mergeBitStream(); 1716 1717 if($bstream == null) { 1718 return null; 1719 } 1720 1721 $ret = $this->appendPaddingBit($bstream); 1722 if($ret < 0) { 1723 return null; 1724 } 1725 1726 return $bstream; 1727 } 1728 1729 //---------------------------------------------------------------------- 1730 public function getByteStream() 1731 { 1732 $bstream = $this->getBitStream(); 1733 if($bstream == null) { 1734 return null; 1735 } 1736 1737 return $bstream->toByte(); 1738 } 1739 } 1740 1741 1742 1743 1744 1745 1746 //---- qrbitstream.php ----------------------------- 1747 1748 1749 1750 1751 /* 1752 * PHP QR Code encoder 1753 * 1754 * Bitstream class 1755 * 1756 * Based on libqrencode C library distributed under LGPL 2.1 1757 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 1758 * 1759 * PHP QR Code is distributed under LGPL 3 1760 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 1761 * 1762 * This library is free software; you can redistribute it and/or 1763 * modify it under the terms of the GNU Lesser General Public 1764 * License as published by the Free Software Foundation; either 1765 * version 3 of the License, or any later version. 1766 * 1767 * This library is distributed in the hope that it will be useful, 1768 * but WITHOUT ANY WARRANTY; without even the implied warranty of 1769 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1770 * Lesser General Public License for more details. 1771 * 1772 * You should have received a copy of the GNU Lesser General Public 1773 * License along with this library; if not, write to the Free Software 1774 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 1775 */ 1776 1777 class QRbitstream { 1778 1779 public $data = array(); 1780 1781 //---------------------------------------------------------------------- 1782 public function size() 1783 { 1784 return count($this->data); 1785 } 1786 1787 //---------------------------------------------------------------------- 1788 public function allocate($setLength) 1789 { 1790 $this->data = array_fill(0, $setLength, 0); 1791 return 0; 1792 } 1793 1794 //---------------------------------------------------------------------- 1795 public static function newFromNum($bits, $num) 1796 { 1797 $bstream = new QRbitstream(); 1798 $bstream->allocate($bits); 1799 1800 $mask = 1 << ($bits - 1); 1801 for($i=0; $i<$bits; $i++) { 1802 if($num & $mask) { 1803 $bstream->data[$i] = 1; 1804 } else { 1805 $bstream->data[$i] = 0; 1806 } 1807 $mask = $mask >> 1; 1808 } 1809 1810 return $bstream; 1811 } 1812 1813 //---------------------------------------------------------------------- 1814 public static function newFromBytes($size, $data) 1815 { 1816 $bstream = new QRbitstream(); 1817 $bstream->allocate($size * 8); 1818 $p=0; 1819 1820 for($i=0; $i<$size; $i++) { 1821 $mask = 0x80; 1822 for($j=0; $j<8; $j++) { 1823 if($data[$i] & $mask) { 1824 $bstream->data[$p] = 1; 1825 } else { 1826 $bstream->data[$p] = 0; 1827 } 1828 $p++; 1829 $mask = $mask >> 1; 1830 } 1831 } 1832 1833 return $bstream; 1834 } 1835 1836 //---------------------------------------------------------------------- 1837 public function append(QRbitstream $arg) 1838 { 1839 if (is_null($arg)) { 1840 return -1; 1841 } 1842 1843 if($arg->size() == 0) { 1844 return 0; 1845 } 1846 1847 if($this->size() == 0) { 1848 $this->data = $arg->data; 1849 return 0; 1850 } 1851 1852 $this->data = array_values(array_merge($this->data, $arg->data)); 1853 1854 return 0; 1855 } 1856 1857 //---------------------------------------------------------------------- 1858 public function appendNum($bits, $num) 1859 { 1860 if ($bits == 0) 1861 return 0; 1862 1863 $b = QRbitstream::newFromNum($bits, $num); 1864 1865 if(is_null($b)) 1866 return -1; 1867 1868 $ret = $this->append($b); 1869 unset($b); 1870 1871 return $ret; 1872 } 1873 1874 //---------------------------------------------------------------------- 1875 public function appendBytes($size, $data) 1876 { 1877 if ($size == 0) 1878 return 0; 1879 1880 $b = QRbitstream::newFromBytes($size, $data); 1881 1882 if(is_null($b)) 1883 return -1; 1884 1885 $ret = $this->append($b); 1886 unset($b); 1887 1888 return $ret; 1889 } 1890 1891 //---------------------------------------------------------------------- 1892 public function toByte() 1893 { 1894 1895 $size = $this->size(); 1896 1897 if($size == 0) { 1898 return array(); 1899 } 1900 1901 $data = array_fill(0, (int)(($size + 7) / 8), 0); 1902 $bytes = (int)($size / 8); 1903 1904 $p = 0; 1905 1906 for($i=0; $i<$bytes; $i++) { 1907 $v = 0; 1908 for($j=0; $j<8; $j++) { 1909 $v = $v << 1; 1910 $v |= $this->data[$p]; 1911 $p++; 1912 } 1913 $data[$i] = $v; 1914 } 1915 1916 if($size & 7) { 1917 $v = 0; 1918 for($j=0; $j<($size & 7); $j++) { 1919 $v = $v << 1; 1920 $v |= $this->data[$p]; 1921 $p++; 1922 } 1923 $data[$bytes] = $v; 1924 } 1925 1926 return $data; 1927 } 1928 1929 } 1930 1931 1932 1933 1934 //---- qrsplit.php ----------------------------- 1935 1936 1937 1938 1939 /* 1940 * PHP QR Code encoder 1941 * 1942 * Input splitting classes 1943 * 1944 * Based on libqrencode C library distributed under LGPL 2.1 1945 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 1946 * 1947 * PHP QR Code is distributed under LGPL 3 1948 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 1949 * 1950 * The following data / specifications are taken from 1951 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) 1952 * or 1953 * "Automatic identification and data capture techniques -- 1954 * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) 1955 * 1956 * This library is free software; you can redistribute it and/or 1957 * modify it under the terms of the GNU Lesser General Public 1958 * License as published by the Free Software Foundation; either 1959 * version 3 of the License, or any later version. 1960 * 1961 * This library is distributed in the hope that it will be useful, 1962 * but WITHOUT ANY WARRANTY; without even the implied warranty of 1963 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1964 * Lesser General Public License for more details. 1965 * 1966 * You should have received a copy of the GNU Lesser General Public 1967 * License along with this library; if not, write to the Free Software 1968 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 1969 */ 1970 class QRsplit { 1971 1972 public $dataStr = ''; 1973 public $input; 1974 public $modeHint; 1975 1976 //---------------------------------------------------------------------- 1977 public function __construct($dataStr, $input, $modeHint) 1978 { 1979 $this->dataStr = $dataStr; 1980 $this->input = $input; 1981 $this->modeHint = $modeHint; 1982 } 1983 1984 //---------------------------------------------------------------------- 1985 public static function isdigitat($str, $pos) 1986 { 1987 if ($pos >= strlen($str)) 1988 return false; 1989 1990 return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9'))); 1991 } 1992 1993 //---------------------------------------------------------------------- 1994 public static function isalnumat($str, $pos) 1995 { 1996 if ($pos >= strlen($str)) 1997 return false; 1998 1999 return (QRinput::lookAnTable(ord($str[$pos])) >= 0); 2000 } 2001 2002 //---------------------------------------------------------------------- 2003 public function identifyMode($pos) 2004 { 2005 if ($pos >= strlen($this->dataStr)) 2006 return QR_MODE_NUL; 2007 2008 $c = $this->dataStr[$pos]; 2009 2010 if(self::isdigitat($this->dataStr, $pos)) { 2011 return QR_MODE_NUM; 2012 } else if(self::isalnumat($this->dataStr, $pos)) { 2013 return QR_MODE_AN; 2014 } else if($this->modeHint == QR_MODE_KANJI) { 2015 2016 if ($pos+1 < strlen($this->dataStr)) 2017 { 2018 $d = $this->dataStr[$pos+1]; 2019 $word = (ord($c) << 8) | ord($d); 2020 if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) { 2021 return QR_MODE_KANJI; 2022 } 2023 } 2024 } 2025 2026 return QR_MODE_8; 2027 } 2028 2029 //---------------------------------------------------------------------- 2030 public function eatNum() 2031 { 2032 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); 2033 2034 $p = 0; 2035 while(self::isdigitat($this->dataStr, $p)) { 2036 $p++; 2037 } 2038 2039 $run = $p; 2040 $mode = $this->identifyMode($p); 2041 2042 if($mode == QR_MODE_8) { 2043 $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln 2044 + QRinput::estimateBitsMode8(1) // + 4 + l8 2045 - QRinput::estimateBitsMode8($run + 1); // - 4 - l8 2046 if($dif > 0) { 2047 return $this->eat8(); 2048 } 2049 } 2050 if($mode == QR_MODE_AN) { 2051 $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln 2052 + QRinput::estimateBitsModeAn(1) // + 4 + la 2053 - QRinput::estimateBitsModeAn($run + 1);// - 4 - la 2054 if($dif > 0) { 2055 return $this->eatAn(); 2056 } 2057 } 2058 2059 $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr)); 2060 if($ret < 0) 2061 return -1; 2062 2063 return $run; 2064 } 2065 2066 //---------------------------------------------------------------------- 2067 public function eatAn() 2068 { 2069 $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion()); 2070 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); 2071 2072 $p = 0; 2073 2074 while(self::isalnumat($this->dataStr, $p)) { 2075 if(self::isdigitat($this->dataStr, $p)) { 2076 $q = $p; 2077 while(self::isdigitat($this->dataStr, $q)) { 2078 $q++; 2079 } 2080 2081 $dif = QRinput::estimateBitsModeAn($p) // + 4 + la 2082 + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln 2083 - QRinput::estimateBitsModeAn($q); // - 4 - la 2084 2085 if($dif < 0) { 2086 break; 2087 } else { 2088 $p = $q; 2089 } 2090 } else { 2091 $p++; 2092 } 2093 } 2094 2095 $run = $p; 2096 2097 if(!self::isalnumat($this->dataStr, $p)) { 2098 $dif = QRinput::estimateBitsModeAn($run) + 4 + $la 2099 + QRinput::estimateBitsMode8(1) // + 4 + l8 2100 - QRinput::estimateBitsMode8($run + 1); // - 4 - l8 2101 if($dif > 0) { 2102 return $this->eat8(); 2103 } 2104 } 2105 2106 $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr)); 2107 if($ret < 0) 2108 return -1; 2109 2110 return $run; 2111 } 2112 2113 //---------------------------------------------------------------------- 2114 public function eatKanji() 2115 { 2116 $p = 0; 2117 2118 while($this->identifyMode($p) == QR_MODE_KANJI) { 2119 $p += 2; 2120 } 2121 2122 $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr)); 2123 if($ret < 0) 2124 return -1; 2125 2126 return $run; 2127 } 2128 2129 //---------------------------------------------------------------------- 2130 public function eat8() 2131 { 2132 $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion()); 2133 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); 2134 2135 $p = 1; 2136 $dataStrLen = strlen($this->dataStr); 2137 2138 while($p < $dataStrLen) { 2139 2140 $mode = $this->identifyMode($p); 2141 if($mode == QR_MODE_KANJI) { 2142 break; 2143 } 2144 if($mode == QR_MODE_NUM) { 2145 $q = $p; 2146 while(self::isdigitat($this->dataStr, $q)) { 2147 $q++; 2148 } 2149 $dif = QRinput::estimateBitsMode8($p) // + 4 + l8 2150 + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln 2151 - QRinput::estimateBitsMode8($q); // - 4 - l8 2152 if($dif < 0) { 2153 break; 2154 } else { 2155 $p = $q; 2156 } 2157 } else if($mode == QR_MODE_AN) { 2158 $q = $p; 2159 while(self::isalnumat($this->dataStr, $q)) { 2160 $q++; 2161 } 2162 $dif = QRinput::estimateBitsMode8($p) // + 4 + l8 2163 + QRinput::estimateBitsModeAn($q - $p) + 4 + $la 2164 - QRinput::estimateBitsMode8($q); // - 4 - l8 2165 if($dif < 0) { 2166 break; 2167 } else { 2168 $p = $q; 2169 } 2170 } else { 2171 $p++; 2172 } 2173 } 2174 2175 $run = $p; 2176 $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr)); 2177 2178 if($ret < 0) 2179 return -1; 2180 2181 return $run; 2182 } 2183 2184 //---------------------------------------------------------------------- 2185 public function splitString() 2186 { 2187 while (strlen($this->dataStr) > 0) 2188 { 2189 if($this->dataStr == '') 2190 return 0; 2191 2192 $mode = $this->identifyMode(0); 2193 2194 switch ($mode) { 2195 case QR_MODE_NUM: $length = $this->eatNum(); break; 2196 case QR_MODE_AN: $length = $this->eatAn(); break; 2197 case QR_MODE_KANJI: 2198 if ($hint == QR_MODE_KANJI) 2199 $length = $this->eatKanji(); 2200 else $length = $this->eat8(); 2201 break; 2202 default: $length = $this->eat8(); break; 2203 2204 } 2205 2206 if($length == 0) return 0; 2207 if($length < 0) return -1; 2208 2209 $this->dataStr = substr($this->dataStr, $length); 2210 } 2211 } 2212 2213 //---------------------------------------------------------------------- 2214 public function toUpper() 2215 { 2216 $stringLen = strlen($this->dataStr); 2217 $p = 0; 2218 2219 while ($p<$stringLen) { 2220 $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint); 2221 if($mode == QR_MODE_KANJI) { 2222 $p += 2; 2223 } else { 2224 if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) { 2225 $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32); 2226 } 2227 $p++; 2228 } 2229 } 2230 2231 return $this->dataStr; 2232 } 2233 2234 //---------------------------------------------------------------------- 2235 public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true) 2236 { 2237 if(is_null($string) || $string == '\0' || $string == '') { 2238 throw new Exception('empty string!!!'); 2239 } 2240 2241 $split = new QRsplit($string, $input, $modeHint); 2242 2243 if(!$casesensitive) 2244 $split->toUpper(); 2245 2246 return $split->splitString(); 2247 } 2248 } 2249 2250 2251 2252 //---- qrrscode.php ----------------------------- 2253 2254 2255 2256 2257 /* 2258 * PHP QR Code encoder 2259 * 2260 * Reed-Solomon error correction support 2261 * 2262 * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q 2263 * (libfec is released under the GNU Lesser General Public License.) 2264 * 2265 * Based on libqrencode C library distributed under LGPL 2.1 2266 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 2267 * 2268 * PHP QR Code is distributed under LGPL 3 2269 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 2270 * 2271 * This library is free software; you can redistribute it and/or 2272 * modify it under the terms of the GNU Lesser General Public 2273 * License as published by the Free Software Foundation; either 2274 * version 3 of the License, or any later version. 2275 * 2276 * This library is distributed in the hope that it will be useful, 2277 * but WITHOUT ANY WARRANTY; without even the implied warranty of 2278 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2279 * Lesser General Public License for more details. 2280 * 2281 * You should have received a copy of the GNU Lesser General Public 2282 * License along with this library; if not, write to the Free Software 2283 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 2284 */ 2285 2286 class QRrsItem { 2287 2288 public $mm; // Bits per symbol 2289 public $nn; // Symbols per block (= (1<<mm)-1) 2290 public $alpha_to = array(); // log lookup table 2291 public $index_of = array(); // Antilog lookup table 2292 public $genpoly = array(); // Generator polynomial 2293 public $nroots; // Number of generator roots = number of parity symbols 2294 public $fcr; // First consecutive root, index form 2295 public $prim; // Primitive element, index form 2296 public $iprim; // prim-th root of 1, index form 2297 public $pad; // Padding bytes in shortened block 2298 public $gfpoly; 2299 2300 //---------------------------------------------------------------------- 2301 public function modnn($x) 2302 { 2303 while ($x >= $this->nn) { 2304 $x -= $this->nn; 2305 $x = ($x >> $this->mm) + ($x & $this->nn); 2306 } 2307 2308 return $x; 2309 } 2310 2311 //---------------------------------------------------------------------- 2312 public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) 2313 { 2314 // Common code for intializing a Reed-Solomon control block (char or int symbols) 2315 // Copyright 2004 Phil Karn, KA9Q 2316 // May be used under the terms of the GNU Lesser General Public License (LGPL) 2317 2318 $rs = null; 2319 2320 // Check parameter ranges 2321 if($symsize < 0 || $symsize > 8) return $rs; 2322 if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs; 2323 if($prim <= 0 || $prim >= (1<<$symsize)) return $rs; 2324 if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values! 2325 if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding 2326 2327 $rs = new QRrsItem(); 2328 $rs->mm = $symsize; 2329 $rs->nn = (1<<$symsize)-1; 2330 $rs->pad = $pad; 2331 2332 $rs->alpha_to = array_fill(0, $rs->nn+1, 0); 2333 $rs->index_of = array_fill(0, $rs->nn+1, 0); 2334 2335 // PHP style macro replacement ;) 2336 $NN =& $rs->nn; 2337 $A0 =& $NN; 2338 2339 // Generate Galois field lookup tables 2340 $rs->index_of[0] = $A0; // log(zero) = -inf 2341 $rs->alpha_to[$A0] = 0; // alpha**-inf = 0 2342 $sr = 1; 2343 2344 for($i=0; $i<$rs->nn; $i++) { 2345 $rs->index_of[$sr] = $i; 2346 $rs->alpha_to[$i] = $sr; 2347 $sr <<= 1; 2348 if($sr & (1<<$symsize)) { 2349 $sr ^= $gfpoly; 2350 } 2351 $sr &= $rs->nn; 2352 } 2353 2354 if($sr != 1){ 2355 // field generator polynomial is not primitive! 2356 $rs = NULL; 2357 return $rs; 2358 } 2359 2360 /* Form RS code generator polynomial from its roots */ 2361 $rs->genpoly = array_fill(0, $nroots+1, 0); 2362 2363 $rs->fcr = $fcr; 2364 $rs->prim = $prim; 2365 $rs->nroots = $nroots; 2366 $rs->gfpoly = $gfpoly; 2367 2368 /* Find prim-th root of 1, used in decoding */ 2369 for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn) 2370 ; // intentional empty-body loop! 2371 2372 $rs->iprim = (int)($iprim / $prim); 2373 $rs->genpoly[0] = 1; 2374 2375 for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) { 2376 $rs->genpoly[$i+1] = 1; 2377 2378 // Multiply rs->genpoly[] by @**(root + x) 2379 for ($j = $i; $j > 0; $j--) { 2380 if ($rs->genpoly[$j] != 0) { 2381 $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)]; 2382 } else { 2383 $rs->genpoly[$j] = $rs->genpoly[$j-1]; 2384 } 2385 } 2386 // rs->genpoly[0] can never be zero 2387 $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)]; 2388 } 2389 2390 // convert rs->genpoly[] to index form for quicker encoding 2391 for ($i = 0; $i <= $nroots; $i++) 2392 $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]]; 2393 2394 return $rs; 2395 } 2396 2397 //---------------------------------------------------------------------- 2398 public function encode_rs_char($data, &$parity) 2399 { 2400 $MM =& $this->mm; 2401 $NN =& $this->nn; 2402 $ALPHA_TO =& $this->alpha_to; 2403 $INDEX_OF =& $this->index_of; 2404 $GENPOLY =& $this->genpoly; 2405 $NROOTS =& $this->nroots; 2406 $FCR =& $this->fcr; 2407 $PRIM =& $this->prim; 2408 $IPRIM =& $this->iprim; 2409 $PAD =& $this->pad; 2410 $A0 =& $NN; 2411 2412 $parity = array_fill(0, $NROOTS, 0); 2413 2414 for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) { 2415 2416 $feedback = $INDEX_OF[$data[$i] ^ $parity[0]]; 2417 if($feedback != $A0) { 2418 // feedback term is non-zero 2419 2420 // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must 2421 // always be for the polynomials constructed by init_rs() 2422 $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback); 2423 2424 for($j=1;$j<$NROOTS;$j++) { 2425 $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])]; 2426 } 2427 } 2428 2429 // Shift 2430 array_shift($parity); 2431 if($feedback != $A0) { 2432 array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]); 2433 } else { 2434 array_push($parity, 0); 2435 } 2436 } 2437 } 2438 } 2439 2440 //########################################################################## 2441 2442 class QRrs { 2443 2444 public static $items = array(); 2445 2446 //---------------------------------------------------------------------- 2447 public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) 2448 { 2449 foreach(self::$items as $rs) { 2450 if($rs->pad != $pad) continue; 2451 if($rs->nroots != $nroots) continue; 2452 if($rs->mm != $symsize) continue; 2453 if($rs->gfpoly != $gfpoly) continue; 2454 if($rs->fcr != $fcr) continue; 2455 if($rs->prim != $prim) continue; 2456 2457 return $rs; 2458 } 2459 2460 $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad); 2461 array_unshift(self::$items, $rs); 2462 2463 return $rs; 2464 } 2465 } 2466 2467 2468 2469 //---- qrmask.php ----------------------------- 2470 2471 2472 2473 2474 /* 2475 * PHP QR Code encoder 2476 * 2477 * Masking 2478 * 2479 * Based on libqrencode C library distributed under LGPL 2.1 2480 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 2481 * 2482 * PHP QR Code is distributed under LGPL 3 2483 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 2484 * 2485 * This library is free software; you can redistribute it and/or 2486 * modify it under the terms of the GNU Lesser General Public 2487 * License as published by the Free Software Foundation; either 2488 * version 3 of the License, or any later version. 2489 * 2490 * This library is distributed in the hope that it will be useful, 2491 * but WITHOUT ANY WARRANTY; without even the implied warranty of 2492 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2493 * Lesser General Public License for more details. 2494 * 2495 * You should have received a copy of the GNU Lesser General Public 2496 * License along with this library; if not, write to the Free Software 2497 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 2498 */ 2499 2500 define('N1', 3); 2501 define('N2', 3); 2502 define('N3', 40); 2503 define('N4', 10); 2504 2505 class QRmask { 2506 2507 public $runLength = array(); 2508 2509 //---------------------------------------------------------------------- 2510 public function __construct() 2511 { 2512 $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0); 2513 } 2514 2515 //---------------------------------------------------------------------- 2516 public function writeFormatInformation($width, &$frame, $mask, $level) 2517 { 2518 $blacks = 0; 2519 $format = QRspec::getFormatInfo($mask, $level); 2520 2521 for($i=0; $i<8; $i++) { 2522 if($format & 1) { 2523 $blacks += 2; 2524 $v = 0x85; 2525 } else { 2526 $v = 0x84; 2527 } 2528 2529 $frame[8][$width - 1 - $i] = chr($v); 2530 if($i < 6) { 2531 $frame[$i][8] = chr($v); 2532 } else { 2533 $frame[$i + 1][8] = chr($v); 2534 } 2535 $format = $format >> 1; 2536 } 2537 2538 for($i=0; $i<7; $i++) { 2539 if($format & 1) { 2540 $blacks += 2; 2541 $v = 0x85; 2542 } else { 2543 $v = 0x84; 2544 } 2545 2546 $frame[$width - 7 + $i][8] = chr($v); 2547 if($i == 0) { 2548 $frame[8][7] = chr($v); 2549 } else { 2550 $frame[8][6 - $i] = chr($v); 2551 } 2552 2553 $format = $format >> 1; 2554 } 2555 2556 return $blacks; 2557 } 2558 2559 //---------------------------------------------------------------------- 2560 public function mask0($x, $y) { return ($x+$y)&1; } 2561 public function mask1($x, $y) { return ($y&1); } 2562 public function mask2($x, $y) { return ($x%3); } 2563 public function mask3($x, $y) { return ($x+$y)%3; } 2564 public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; } 2565 public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; } 2566 public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; } 2567 public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; } 2568 2569 //---------------------------------------------------------------------- 2570 private function generateMaskNo($maskNo, $width, $frame) 2571 { 2572 $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); 2573 2574 for($y=0; $y<$width; $y++) { 2575 for($x=0; $x<$width; $x++) { 2576 if(ord($frame[$y][$x]) & 0x80) { 2577 $bitMask[$y][$x] = 0; 2578 } else { 2579 $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y); 2580 $bitMask[$y][$x] = ($maskFunc == 0)?1:0; 2581 } 2582 2583 } 2584 } 2585 2586 return $bitMask; 2587 } 2588 2589 //---------------------------------------------------------------------- 2590 public static function serial($bitFrame) 2591 { 2592 $codeArr = array(); 2593 2594 foreach ($bitFrame as $line) 2595 $codeArr[] = join('', $line); 2596 2597 return gzcompress(join("\n", $codeArr), 9); 2598 } 2599 2600 //---------------------------------------------------------------------- 2601 public static function unserial($code) 2602 { 2603 $codeArr = array(); 2604 2605 $codeLines = explode("\n", gzuncompress($code)); 2606 foreach ($codeLines as $line) 2607 $codeArr[] = str_split($line); 2608 2609 return $codeArr; 2610 } 2611 2612 //---------------------------------------------------------------------- 2613 public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) 2614 { 2615 $b = 0; 2616 $bitMask = array(); 2617 2618 $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat'; 2619 2620 if (QR_CACHEABLE) { 2621 if (file_exists($fileName)) { 2622 $bitMask = self::unserial(file_get_contents($fileName)); 2623 } else { 2624 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); 2625 if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo)) 2626 mkdir(QR_CACHE_DIR.'mask_'.$maskNo); 2627 file_put_contents($fileName, self::serial($bitMask)); 2628 } 2629 } else { 2630 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); 2631 } 2632 2633 if ($maskGenOnly) 2634 return; 2635 2636 $d = $s; 2637 2638 for($y=0; $y<$width; $y++) { 2639 for($x=0; $x<$width; $x++) { 2640 if($bitMask[$y][$x] == 1) { 2641 $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]); 2642 } 2643 $b += (int)(ord($d[$y][$x]) & 1); 2644 } 2645 } 2646 2647 return $b; 2648 } 2649 2650 //---------------------------------------------------------------------- 2651 public function makeMask($width, $frame, $maskNo, $level) 2652 { 2653 $masked = array_fill(0, $width, str_repeat("\0", $width)); 2654 $this->makeMaskNo($maskNo, $width, $frame, $masked); 2655 $this->writeFormatInformation($width, $masked, $maskNo, $level); 2656 2657 return $masked; 2658 } 2659 2660 //---------------------------------------------------------------------- 2661 public function calcN1N3($length) 2662 { 2663 $demerit = 0; 2664 2665 for($i=0; $i<$length; $i++) { 2666 2667 if($this->runLength[$i] >= 5) { 2668 $demerit += (N1 + ($this->runLength[$i] - 5)); 2669 } 2670 if($i & 1) { 2671 if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) { 2672 $fact = (int)($this->runLength[$i] / 3); 2673 if(($this->runLength[$i-2] == $fact) && 2674 ($this->runLength[$i-1] == $fact) && 2675 ($this->runLength[$i+1] == $fact) && 2676 ($this->runLength[$i+2] == $fact)) { 2677 if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) { 2678 $demerit += N3; 2679 } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) { 2680 $demerit += N3; 2681 } 2682 } 2683 } 2684 } 2685 } 2686 return $demerit; 2687 } 2688 2689 //---------------------------------------------------------------------- 2690 public function evaluateSymbol($width, $frame) 2691 { 2692 $head = 0; 2693 $demerit = 0; 2694 2695 for($y=0; $y<$width; $y++) { 2696 $head = 0; 2697 $this->runLength[0] = 1; 2698 2699 $frameY = $frame[$y]; 2700 2701 if ($y>0) 2702 $frameYM = $frame[$y-1]; 2703 2704 for($x=0; $x<$width; $x++) { 2705 if(($x > 0) && ($y > 0)) { 2706 $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]); 2707 $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]); 2708 2709 if(($b22 | ($w22 ^ 1))&1) { 2710 $demerit += N2; 2711 } 2712 } 2713 if(($x == 0) && (ord($frameY[$x]) & 1)) { 2714 $this->runLength[0] = -1; 2715 $head = 1; 2716 $this->runLength[$head] = 1; 2717 } else if($x > 0) { 2718 if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) { 2719 $head++; 2720 $this->runLength[$head] = 1; 2721 } else { 2722 $this->runLength[$head]++; 2723 } 2724 } 2725 } 2726 2727 $demerit += $this->calcN1N3($head+1); 2728 } 2729 2730 for($x=0; $x<$width; $x++) { 2731 $head = 0; 2732 $this->runLength[0] = 1; 2733 2734 for($y=0; $y<$width; $y++) { 2735 if($y == 0 && (ord($frame[$y][$x]) & 1)) { 2736 $this->runLength[0] = -1; 2737 $head = 1; 2738 $this->runLength[$head] = 1; 2739 } else if($y > 0) { 2740 if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) { 2741 $head++; 2742 $this->runLength[$head] = 1; 2743 } else { 2744 $this->runLength[$head]++; 2745 } 2746 } 2747 } 2748 2749 $demerit += $this->calcN1N3($head+1); 2750 } 2751 2752 return $demerit; 2753 } 2754 2755 2756 //---------------------------------------------------------------------- 2757 public function mask($width, $frame, $level) 2758 { 2759 $minDemerit = PHP_INT_MAX; 2760 $bestMaskNum = 0; 2761 $bestMask = array(); 2762 2763 $checked_masks = array(0,1,2,3,4,5,6,7); 2764 2765 if (QR_FIND_FROM_RANDOM !== false) { 2766 2767 $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9); 2768 for ($i = 0; $i < $howManuOut; $i++) { 2769 $remPos = rand (0, count($checked_masks)-1); 2770 unset($checked_masks[$remPos]); 2771 $checked_masks = array_values($checked_masks); 2772 } 2773 2774 } 2775 2776 $bestMask = $frame; 2777 2778 foreach($checked_masks as $i) { 2779 $mask = array_fill(0, $width, str_repeat("\0", $width)); 2780 2781 $demerit = 0; 2782 $blacks = 0; 2783 $blacks = $this->makeMaskNo($i, $width, $frame, $mask); 2784 $blacks += $this->writeFormatInformation($width, $mask, $i, $level); 2785 $blacks = (int)(100 * $blacks / ($width * $width)); 2786 $demerit = (int)((int)(abs($blacks - 50) / 5) * N4); 2787 $demerit += $this->evaluateSymbol($width, $mask); 2788 2789 if($demerit < $minDemerit) { 2790 $minDemerit = $demerit; 2791 $bestMask = $mask; 2792 $bestMaskNum = $i; 2793 } 2794 } 2795 2796 return $bestMask; 2797 } 2798 2799 //---------------------------------------------------------------------- 2800 } 2801 2802 2803 2804 2805 //---- qrencode.php ----------------------------- 2806 2807 2808 2809 2810 /* 2811 * PHP QR Code encoder 2812 * 2813 * Main encoder classes. 2814 * 2815 * Based on libqrencode C library distributed under LGPL 2.1 2816 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net> 2817 * 2818 * PHP QR Code is distributed under LGPL 3 2819 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> 2820 * 2821 * This library is free software; you can redistribute it and/or 2822 * modify it under the terms of the GNU Lesser General Public 2823 * License as published by the Free Software Foundation; either 2824 * version 3 of the License, or any later version. 2825 * 2826 * This library is distributed in the hope that it will be useful, 2827 * but WITHOUT ANY WARRANTY; without even the implied warranty of 2828 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2829 * Lesser General Public License for more details. 2830 * 2831 * You should have received a copy of the GNU Lesser General Public 2832 * License along with this library; if not, write to the Free Software 2833 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 2834 */ 2835 2836 class QRrsblock { 2837 public $dataLength; 2838 public $data = array(); 2839 public $eccLength; 2840 public $ecc = array(); 2841 2842 public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs) 2843 { 2844 $rs->encode_rs_char($data, $ecc); 2845 2846 $this->dataLength = $dl; 2847 $this->data = $data; 2848 $this->eccLength = $el; 2849 $this->ecc = $ecc; 2850 } 2851 }; 2852 2853 //########################################################################## 2854 2855 class QRrawcode { 2856 public $version; 2857 public $datacode = array(); 2858 public $ecccode = array(); 2859 public $blocks; 2860 public $rsblocks = array(); //of RSblock 2861 public $count; 2862 public $dataLength; 2863 public $eccLength; 2864 public $b1; 2865 2866 //---------------------------------------------------------------------- 2867 public function __construct(QRinput $input) 2868 { 2869 $spec = array(0,0,0,0,0); 2870 2871 $this->datacode = $input->getByteStream(); 2872 if(is_null($this->datacode)) { 2873 throw new Exception('null imput string'); 2874 } 2875 2876 QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec); 2877 2878 $this->version = $input->getVersion(); 2879 $this->b1 = QRspec::rsBlockNum1($spec); 2880 $this->dataLength = QRspec::rsDataLength($spec); 2881 $this->eccLength = QRspec::rsEccLength($spec); 2882 $this->ecccode = array_fill(0, $this->eccLength, 0); 2883 $this->blocks = QRspec::rsBlockNum($spec); 2884 2885 $ret = $this->init($spec); 2886 if($ret < 0) { 2887 throw new Exception('block alloc error'); 2888 return null; 2889 } 2890 2891 $this->count = 0; 2892 } 2893 2894 //---------------------------------------------------------------------- 2895 public function init(array $spec) 2896 { 2897 $dl = QRspec::rsDataCodes1($spec); 2898 $el = QRspec::rsEccCodes1($spec); 2899 $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); 2900 2901 2902 $blockNo = 0; 2903 $dataPos = 0; 2904 $eccPos = 0; 2905 for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) { 2906 $ecc = array_slice($this->ecccode,$eccPos); 2907 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs); 2908 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc); 2909 2910 $dataPos += $dl; 2911 $eccPos += $el; 2912 $blockNo++; 2913 } 2914 2915 if(QRspec::rsBlockNum2($spec) == 0) 2916 return 0; 2917 2918 $dl = QRspec::rsDataCodes2($spec); 2919 $el = QRspec::rsEccCodes2($spec); 2920 $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); 2921 2922 if($rs == NULL) return -1; 2923 2924 for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) { 2925 $ecc = array_slice($this->ecccode,$eccPos); 2926 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs); 2927 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc); 2928 2929 $dataPos += $dl; 2930 $eccPos += $el; 2931 $blockNo++; 2932 } 2933 2934 return 0; 2935 } 2936 2937 //---------------------------------------------------------------------- 2938 public function getCode() 2939 { 2940 $ret; 2941 2942 if($this->count < $this->dataLength) { 2943 $row = $this->count % $this->blocks; 2944 $col = $this->count / $this->blocks; 2945 if($col >= $this->rsblocks[0]->dataLength) { 2946 $row += $this->b1; 2947 } 2948 $ret = $this->rsblocks[$row]->data[$col]; 2949 } else if($this->count < $this->dataLength + $this->eccLength) { 2950 $row = ($this->count - $this->dataLength) % $this->blocks; 2951 $col = ($this->count - $this->dataLength) / $this->blocks; 2952 $ret = $this->rsblocks[$row]->ecc[$col]; 2953 } else { 2954 return 0; 2955 } 2956 $this->count++; 2957 2958 return $ret; 2959 } 2960 } 2961 2962 //########################################################################## 2963 2964 class QRcode { 2965 2966 public $version; 2967 public $width; 2968 public $data; 2969 2970 //---------------------------------------------------------------------- 2971 public function encodeMask(QRinput $input, $mask) 2972 { 2973 if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) { 2974 throw new Exception('wrong version'); 2975 } 2976 if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) { 2977 throw new Exception('wrong level'); 2978 } 2979 2980 $raw = new QRrawcode($input); 2981 2982 QRtools::markTime('after_raw'); 2983 2984 $version = $raw->version; 2985 $width = QRspec::getWidth($version); 2986 $frame = QRspec::newFrame($version); 2987 2988 $filler = new FrameFiller($width, $frame); 2989 if(is_null($filler)) { 2990 return NULL; 2991 } 2992 2993 // inteleaved data and ecc codes 2994 for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) { 2995 $code = $raw->getCode(); 2996 $bit = 0x80; 2997 for($j=0; $j<8; $j++) { 2998 $addr = $filler->next(); 2999 $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0)); 3000 $bit = $bit >> 1; 3001 } 3002 } 3003 3004 QRtools::markTime('after_filler'); 3005 3006 unset($raw); 3007 3008 // remainder bits 3009 $j = QRspec::getRemainder($version); 3010 for($i=0; $i<$j; $i++) { 3011 $addr = $filler->next(); 3012 $filler->setFrameAt($addr, 0x02); 3013 } 3014 3015 $frame = $filler->frame; 3016 unset($filler); 3017 3018 3019 // masking 3020 $maskObj = new QRmask(); 3021 if($mask < 0) { 3022 3023 if (QR_FIND_BEST_MASK) { 3024 $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel()); 3025 } else { 3026 $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel()); 3027 } 3028 } else { 3029 $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel()); 3030 } 3031 3032 if($masked == NULL) { 3033 return NULL; 3034 } 3035 3036 QRtools::markTime('after_mask'); 3037 3038 $this->version = $version; 3039 $this->width = $width; 3040 $this->data = $masked; 3041 3042 return $this; 3043 } 3044 3045 //---------------------------------------------------------------------- 3046 public function encodeInput(QRinput $input) 3047 { 3048 return $this->encodeMask($input, -1); 3049 } 3050 3051 //---------------------------------------------------------------------- 3052 public function encodeString8bit($string, $version, $level) 3053 { 3054 if(string == NULL) { 3055 throw new Exception('empty string!'); 3056 return NULL; 3057 } 3058 3059 $input = new QRinput($version, $level); 3060 if($input == NULL) return NULL; 3061 3062 $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string)); 3063 if($ret < 0) { 3064 unset($input); 3065 return NULL; 3066 } 3067 return $this->encodeInput($input); 3068 } 3069 3070 //---------------------------------------------------------------------- 3071 public function encodeString($string, $version, $level, $hint, $casesensitive) 3072 { 3073 3074 if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) { 3075 throw new Exception('bad hint'); 3076 return NULL; 3077 } 3078 3079 $input = new QRinput($version, $level); 3080 if($input == NULL) return NULL; 3081 3082 $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive); 3083 if($ret < 0) { 3084 return NULL; 3085 } 3086 3087 return $this->encodeInput($input); 3088 } 3089 3090 //---------------------------------------------------------------------- 3091 public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) 3092 { 3093 $enc = QRencode::factory($level, $size, $margin); 3094 return $enc->encodePNG($text, $outfile, $saveandprint=false); 3095 } 3096 3097 //---------------------------------------------------------------------- 3098 public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 3099 { 3100 $enc = QRencode::factory($level, $size, $margin); 3101 return $enc->encode($text, $outfile); 3102 } 3103 3104 //---------------------------------------------------------------------- 3105 public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 3106 { 3107 $enc = QRencode::factory($level, $size, $margin); 3108 return $enc->encodeRAW($text, $outfile); 3109 } 3110 } 3111 3112 //########################################################################## 3113 3114 class FrameFiller { 3115 3116 public $width; 3117 public $frame; 3118 public $x; 3119 public $y; 3120 public $dir; 3121 public $bit; 3122 3123 //---------------------------------------------------------------------- 3124 public function __construct($width, &$frame) 3125 { 3126 $this->width = $width; 3127 $this->frame = $frame; 3128 $this->x = $width - 1; 3129 $this->y = $width - 1; 3130 $this->dir = -1; 3131 $this->bit = -1; 3132 } 3133 3134 //---------------------------------------------------------------------- 3135 public function setFrameAt($at, $val) 3136 { 3137 $this->frame[$at['y']][$at['x']] = chr($val); 3138 } 3139 3140 //---------------------------------------------------------------------- 3141 public function getFrameAt($at) 3142 { 3143 return ord($this->frame[$at['y']][$at['x']]); 3144 } 3145 3146 //---------------------------------------------------------------------- 3147 public function next() 3148 { 3149 do { 3150 3151 if($this->bit == -1) { 3152 $this->bit = 0; 3153 return array('x'=>$this->x, 'y'=>$this->y); 3154 } 3155 3156 $x = $this->x; 3157 $y = $this->y; 3158 $w = $this->width; 3159 3160 if($this->bit == 0) { 3161 $x--; 3162 $this->bit++; 3163 } else { 3164 $x++; 3165 $y += $this->dir; 3166 $this->bit--; 3167 } 3168 3169 if($this->dir < 0) { 3170 if($y < 0) { 3171 $y = 0; 3172 $x -= 2; 3173 $this->dir = 1; 3174 if($x == 6) { 3175 $x--; 3176 $y = 9; 3177 } 3178 } 3179 } else { 3180 if($y == $w) { 3181 $y = $w - 1; 3182 $x -= 2; 3183 $this->dir = -1; 3184 if($x == 6) { 3185 $x--; 3186 $y -= 8; 3187 } 3188 } 3189 } 3190 if($x < 0 || $y < 0) return null; 3191 3192 $this->x = $x; 3193 $this->y = $y; 3194 3195 } while(ord($this->frame[$y][$x]) & 0x80); 3196 3197 return array('x'=>$x, 'y'=>$y); 3198 } 3199 3200 } ; 3201 3202 //########################################################################## 3203 3204 class QRencode { 3205 3206 public $casesensitive = true; 3207 public $eightbit = false; 3208 3209 public $version = 0; 3210 public $size = 3; 3211 public $margin = 4; 3212 3213 public $structured = 0; // not supported yet 3214 3215 public $level = QR_ECLEVEL_L; 3216 public $hint = QR_MODE_8; 3217 3218 //---------------------------------------------------------------------- 3219 public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4) 3220 { 3221 $enc = new QRencode(); 3222 $enc->size = $size; 3223 $enc->margin = $margin; 3224 3225 switch ($level.'') { 3226 case '0': 3227 case '1': 3228 case '2': 3229 case '3': 3230 $enc->level = $level; 3231 break; 3232 case 'l': 3233 case 'L': 3234 $enc->level = QR_ECLEVEL_L; 3235 break; 3236 case 'm': 3237 case 'M': 3238 $enc->level = QR_ECLEVEL_M; 3239 break; 3240 case 'q': 3241 case 'Q': 3242 $enc->level = QR_ECLEVEL_Q; 3243 break; 3244 case 'h': 3245 case 'H': 3246 $enc->level = QR_ECLEVEL_H; 3247 break; 3248 } 3249 3250 return $enc; 3251 } 3252 3253 //---------------------------------------------------------------------- 3254 public function encodeRAW($intext, $outfile = false) 3255 { 3256 $code = new QRcode(); 3257 3258 if($this->eightbit) { 3259 $code->encodeString8bit($intext, $this->version, $this->level); 3260 } else { 3261 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive); 3262 } 3263 3264 return $code->data; 3265 } 3266 3267 //---------------------------------------------------------------------- 3268 public function encode($intext, $outfile = false) 3269 { 3270 $code = new QRcode(); 3271 3272 if($this->eightbit) { 3273 $code->encodeString8bit($intext, $this->version, $this->level); 3274 } else { 3275 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive); 3276 } 3277 3278 QRtools::markTime('after_encode'); 3279 3280 if ($outfile!== false) { 3281 file_put_contents($outfile, join("\n", QRtools::binarize($code->data))); 3282 } else { 3283 return QRtools::binarize($code->data); 3284 } 3285 } 3286 3287 //---------------------------------------------------------------------- 3288 public function encodePNG($intext, $outfile = false,$saveandprint=false) 3289 { 3290 try { 3291 3292 ob_start(); 3293 $tab = $this->encode($intext); 3294 $err = ob_get_contents(); 3295 ob_end_clean(); 3296 3297 if ($err != '') 3298 QRtools::log($outfile, $err); 3299 3300 $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin)); 3301 3302 QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint); 3303 3304 } catch (Exception $e) { 3305 3306 QRtools::log($outfile, $e->getMessage()); 3307 3308 } 3309 } 3310 }