php 生成二维码

生成二维码的类:

   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 <fukuchi@megaui.net>
  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, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  75  */
  76  
  77     // Encoding modes
  78      
  79     define('QR_MODE_NUL', -1);
  80     define('QR_MODE_NUM', 0);
  81     define('QR_MODE_AN', 1);
  82     define('QR_MODE_8', 2);
  83     define('QR_MODE_KANJI', 3);
  84     define('QR_MODE_STRUCTURE', 4);
  85 
  86     // Levels of error correction.
  87 
  88     define('QR_ECLEVEL_L', 0);
  89     define('QR_ECLEVEL_M', 1);
  90     define('QR_ECLEVEL_Q', 2);
  91     define('QR_ECLEVEL_H', 3);
  92     
  93     // Supported output formats
  94     
  95     define('QR_FORMAT_TEXT', 0);
  96     define('QR_FORMAT_PNG',  1);
  97     
  98     class qrstr {
  99         public static function set(&$srctab, $x, $y, $repl, $replLen = false) {
 100             $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
 101         }
 102     }    
 103 
 104 
 105 
 106 //---- merged_config.php -----------------------------
 107 
 108 
 109 
 110 
 111 /*
 112  * PHP QR Code encoder
 113  * 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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, $width, 0));
 229                 for ($maskNo=0; $maskNo<8; $maskNo++)
 230                     $mask->makeMaskNo($maskNo, $width, $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', date('Y-m-d H:i:s').': '.$err, 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, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
 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, Inc., 51 Franklin St, Fifth Floor, Boston, 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,    0, 0, array(   0,    0,    0,    0)),
 362             array( 21,   26, 0, array(   7,   10,   13,   17)), // 1
 363             array( 25,   44, 7, array(  10,   16,   22,   28)),
 364             array( 29,   70, 7, array(  15,   26,   36,   44)),
 365             array( 33,  100, 7, array(  20,   36,   52,   64)),
 366             array( 37,  134, 7, array(  26,   48,   72,   88)), // 5
 367             array( 41,  172, 7, array(  36,   64,   96,  112)),
 368             array( 45,  196, 0, array(  40,   72,  108,  130)),
 369             array( 49,  242, 0, array(  48,   88,  132,  156)),
 370             array( 53,  292, 0, array(  60,  110,  160,  192)),
 371             array( 57,  346, 0, array(  72,  130,  192,  224)), //10
 372             array( 61,  404, 0, array(  80,  150,  224,  264)),
 373             array( 65,  466, 0, array(  96,  176,  260,  308)),
 374             array( 69,  532, 0, array( 104,  198,  288,  352)),
 375             array( 73,  581, 3, array( 120,  216,  320,  384)),
 376             array( 77,  655, 3, array( 132,  240,  360,  432)), //15
 377             array( 81,  733, 3, array( 144,  280,  408,  480)),
 378             array( 85,  815, 3, array( 168,  308,  448,  532)),
 379             array( 89,  901, 3, array( 180,  338,  504,  588)),
 380             array( 93,  991, 3, array( 196,  364,  546,  650)),
 381             array( 97, 1085, 3, array( 224,  416,  600,  700)), //20
 382             array(101, 1156, 4, array( 224,  442,  644,  750)),
 383             array(105, 1258, 4, array( 252,  476,  690,  816)),
 384             array(109, 1364, 4, array( 270,  504,  750,  900)),
 385             array(113, 1474, 4, array( 300,  560,  810,  960)),
 386             array(117, 1588, 4, array( 312,  588,  870, 1050)), //25
 387             array(121, 1706, 4, array( 336,  644,  952, 1110)),
 388             array(125, 1828, 4, array( 360,  700, 1020, 1200)),
 389             array(129, 1921, 3, array( 390,  728, 1050, 1260)),
 390             array(133, 2051, 3, array( 420,  784, 1140, 1350)),
 391             array(137, 2185, 3, array( 450,  812, 1200, 1440)), //30
 392             array(141, 2323, 3, array( 480,  868, 1290, 1530)),
 393             array(145, 2465, 3, array( 510,  924, 1350, 1620)),
 394             array(149, 2611, 3, array( 540,  980, 1440, 1710)),
 395             array(153, 2761, 3, array( 570, 1036, 1530, 1800)),
 396             array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35
 397             array(161, 3034, 0, array( 600, 1120, 1680, 1980)),
 398             array(165, 3196, 0, array( 630, 1204, 1770, 2100)),
 399             array(169, 3362, 0, array( 660, 1260, 1860, 2220)),
 400             array(173, 3532, 0, array( 720, 1316, 1950, 2310)),
 401             array(177, 3706, 0, 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, 16),
 447             array( 8, 10, 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,  0), array( 0,  0), array( 0,  0)),
 497             array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), // 1
 498             array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)),
 499             array(array( 1,  0), array( 1,  0), array( 2,  0), array( 2,  0)),
 500             array(array( 1,  0), array( 2,  0), array( 2,  0), array( 4,  0)),
 501             array(array( 1,  0), array( 2,  0), array( 2,  2), array( 2,  2)), // 5
 502             array(array( 2,  0), array( 4,  0), array( 4,  0), array( 4,  0)),
 503             array(array( 2,  0), array( 4,  0), array( 2,  4), array( 4,  1)),
 504             array(array( 2,  0), array( 2,  2), array( 4,  2), array( 4,  2)),
 505             array(array( 2,  0), array( 3,  2), array( 4,  4), array( 4,  4)),
 506             array(array( 2,  2), array( 4,  1), array( 6,  2), array( 6,  2)), //10
 507             array(array( 4,  0), array( 1,  4), array( 4,  4), array( 3,  8)),
 508             array(array( 2,  2), array( 6,  2), array( 4,  6), array( 7,  4)),
 509             array(array( 4,  0), array( 8,  1), array( 8,  4), array(12,  4)),
 510             array(array( 3,  1), array( 4,  5), array(11,  5), array(11,  5)),
 511             array(array( 5,  1), array( 5,  5), array( 5,  7), array(11,  7)), //15
 512             array(array( 5,  1), array( 7,  3), array(15,  2), array( 3, 13)),
 513             array(array( 1,  5), array(10,  1), array( 1, 15), array( 2, 17)),
 514             array(array( 5,  1), array( 9,  4), array(17,  1), array( 2, 19)),
 515             array(array( 3,  4), array( 3, 11), array(17,  4), array( 9, 16)),
 516             array(array( 3,  5), array( 3, 13), array(15,  5), array(15, 10)), //20
 517             array(array( 4,  4), array(17,  0), array(17,  6), array(19,  6)),
 518             array(array( 2,  7), array(17,  0), array( 7, 16), array(34,  0)),
 519             array(array( 4,  5), array( 4, 14), array(11, 14), array(16, 14)),
 520             array(array( 6,  4), array( 6, 14), array(11, 16), array(30,  2)),
 521             array(array( 8,  4), array( 8, 13), array( 7, 22), array(22, 13)), //25
 522             array(array(10,  2), array(19,  4), array(28,  6), array(33,  4)),
 523             array(array( 8,  4), array(22,  3), array( 8, 26), array(12, 28)),
 524             array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)),
 525             array(array( 7,  7), array(21,  7), array( 1, 37), array(19, 26)),
 526             array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30
 527             array(array(13,  3), array( 2, 29), array(42,  1), array(23, 28)),
 528             array(array(17,  0), array(10, 23), array(10, 35), array(19, 35)),
 529             array(array(17,  1), array(14, 21), array(29, 19), array(11, 46)),
 530             array(array(13,  6), array(14, 23), array(44,  7), array(59,  1)),
 531             array(array(12,  7), array(12, 26), array(39, 14), array(22, 41)), //35
 532             array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)),
 533             array(array(17,  4), array(29, 14), array(49, 10), array(24, 46)),
 534             array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)),
 535             array(array(20,  4), array(40,  7), array(43, 22), array(10, 67)),
 536             array(array(19,  6), array(18, 31), array(34, 34), 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,0,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,  0),
 579             array( 0,  0), array(18,  0), array(22,  0), array(26,  0), array(30,  0), // 1- 5
 580             array(34,  0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
 581             array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15
 582             array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20
 583             array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25
 584             array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30
 585             array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35
 586             array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //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                 "\xa1\xa1\xa1\xa1\xa1",
 600                 "\xa1\xa0\xa0\xa0\xa1",
 601                 "\xa1\xa0\xa1\xa0\xa1",
 602                 "\xa1\xa0\xa0\xa0\xa1",
 603                 "\xa1\xa1\xa1\xa1\xa1"
 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, $x, $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, $cx, $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, $ox, $oy)
 709         {
 710             $finder = array(
 711                 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
 712                 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
 713                 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
 714                 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
 715                 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
 716                 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
 717                 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
 718             );                            
 719             
 720             for($y=0; $y<7; $y++) {
 721                 QRstr::set($frame, $ox, $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 ("\0", $width);
 730             $frame = array_fill(0, $width, $frameLine);
 731 
 732             // Finder pattern
 733             self::putFinderPattern($frame, 0, 0);
 734             self::putFinderPattern($frame, $width - 7, 0);
 735             self::putFinderPattern($frame, 0, $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, 0, 7, $setPattern);
 750             QRstr::set($frame, $width-8, 7, $setPattern);
 751             QRstr::set($frame, 0, $width - 8, $setPattern);
 752         
 753             // Format info
 754             $setPattern = str_repeat("\x84", 9);
 755             QRstr::set($frame, 0, 8, $setPattern);
 756             QRstr::set($frame, $width - 8, 8, $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, $frame, $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">&nbsp;&nbsp;</span>', explode('0', $frameLine));
 810                         $frameLine = join('&#9608;&#9608;', explode('1', $frameLine));
 811                     }
 812                     
 813                     ?>
 814                 <style>
 815                     .m { background-color: white; }
 816                 </style>
 817                 <?php
 818                     echo '<pre><tt><br/ ><br/ ><br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
 819                     echo join("<br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", $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">&nbsp;</span>',  explode("\xc0", $frameLine));
 826                     $frameLine = join('<span class="m">&#9618;</span>', explode("\xc1", $frameLine));
 827                     $frameLine = join('<span class="p">&nbsp;</span>',  explode("\xa0", $frameLine));
 828                     $frameLine = join('<span class="p">&#9618;</span>', explode("\xa1", $frameLine));
 829                     $frameLine = join('<span class="s">&#9671;</span>', explode("\x84", $frameLine)); //format 0
 830                     $frameLine = join('<span class="s">&#9670;</span>', explode("\x85", $frameLine)); //format 1
 831                     $frameLine = join('<span class="x">&#9762;</span>', explode("\x81", $frameLine)); //special bit
 832                     $frameLine = join('<span class="c">&nbsp;</span>',  explode("\x90", $frameLine)); //clock 0
 833                     $frameLine = join('<span class="c">&#9719;</span>', explode("\x91", $frameLine)); //clock 1
 834                     $frameLine = join('<span class="f">&nbsp;</span>',  explode("\x88", $frameLine)); //version
 835                     $frameLine = join('<span class="f">&#9618;</span>', explode("\x89", $frameLine)); //version
 836                     $frameLine = join('&#9830;', explode("\x01", $frameLine));
 837                     $frameLine = join('&#8901;', explode("\0", $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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85) 
 968         {
 969             $image = self::image($frame, $pixelPerPoint, $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, $pixelPerPoint = 4, $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,255);
 993             $col[1] = ImageColorAllocate($base_image,0,0,0);
 994 
 995             imagefill($base_image, 0, 0, $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, 0, 0, 0, 0, $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, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, 0, $size);
1060             
1061             if (count($setData) < $size) {
1062                 $setData = array_merge($setData, array_fill(0,$size-count($setData),0));
1063             }
1064         
1065             if(!QRinput::check($mode, $size, $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, $version), $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, $version), $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, $version), (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, $size, $data)
1358         {
1359             try {
1360                 $entry = new QRinputItem($mode, $size, $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, $index, $parity);
1381             
1382             try {
1383                 $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, 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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1442             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1443             36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
1444              0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1,
1445             -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1446             25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
1447             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1448             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, $size, $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, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, $run, 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, $run, 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 == '\0' || $string == '') {
2246                 throw new Exception('empty string!!!');
2247             }
2248 
2249             $split = new QRsplit($string, $input, $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, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, $rs->nn+1, 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, $gfpoly, $fcr, $prim, $nroots, $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, $gfpoly, $fcr, $prim, $nroots, $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, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, &$frame, $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, $width, $frame)
2581         {
2582             $bitMask = array_fill(0, $width, array_fill(0, $width, 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), $x, $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, $width, $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, $width, $s, $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, $width, $s, $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, $frame, $maskNo, $level)
2662         {
2663             $masked = array_fill(0, $width, str_repeat("\0", $width));
2664             $this->makeMaskNo($maskNo, $width, $frame, $masked);
2665             $this->writeFormatInformation($width, $masked, $maskNo, $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, $frame, $level)
2768         {
2769             $minDemerit = PHP_INT_MAX;
2770             $bestMaskNum = 0;
2771             $bestMask = array();
2772             
2773             $checked_masks = array(0,1,2,3,4,5,6,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, str_repeat("\0", $width));
2790 
2791                 $demerit = 0;
2792                 $blacks = 0;
2793                 $blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
2794                 $blacks += $this->writeFormatInformation($width, $mask, $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, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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, Inc., 51 Franklin St, Fifth Floor, Boston, 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, $data, $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,0,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, 0, 1, $el, 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), $el,  $ecc, $rs);
2919                 $this->ecccode = array_merge(array_slice($this->ecccode,0, $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, 0x11d, 0, 1, $el, 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, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
2938                 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $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, $frame, $input->getErrorCorrectionLevel());
3036                 } else {
3037                     $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
3038                 }
3039             } else {
3040                 $masked = $maskObj->makeMask($width, $frame, $mask, $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, $version, $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, $version, $level, $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, $input, $hint, $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, $size, $margin);
3105             return $enc->encodePNG($text, $outfile, $saveandprint=false);
3106         }
3107 
3108         //----------------------------------------------------------------------
3109         public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
3110         {
3111             $enc = QRencode::factory($level, $size, $margin);
3112             return $enc->encode($text, $outfile);
3113         }
3114 
3115         //----------------------------------------------------------------------
3116         public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
3117         {
3118             $enc = QRencode::factory($level, $size, $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, $size = 3, $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->version, $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->version, $this->level);
3285             } else {
3286                 $code->encodeString($intext, $this->version, $this->level, $this->hint, $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, $outfile = false,$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, $outfile, 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     }
View Code

使用方法:

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);

 

posted @ 2019-08-21 08:55  子焱  阅读(325)  评论(0编辑  收藏  举报