PHP生成二维码图片(PNG格式)

项目中需要用到动态生成下载地址的二维码,于是搜到以下代码:

QRcode.php:

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

 

调用:

<?php
   $appUrl = "http://192.168.1.77/cache/appDown.png";
   QRcode::png($appUrl, "cache/appDown.png",'L',4,0);     //生成png图片    
   echo '<img src="'.$appUrl.'" />'; 
?>

 

然后可以在页面直接输出图片啦

 

End.

posted @ 2014-03-27 17:18  lianche  阅读(1348)  评论(0编辑  收藏  举报