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