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"> </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/ > '; 670 echo join("<br/ > ", $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"> </span>', explode("\xc0", $frameLine)); 677 $frameLine = join('<span class="m">?</span>', explode("\xc1", $frameLine)); 678 $frameLine = join('<span class="p"> </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"> </span>', explode("\x90", $frameLine)); //clock 0 684 $frameLine = join('<span class="c">?</span>', explode("\x91", $frameLine)); //clock 1 685 $frameLine = join('<span class="f"> </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 }
调用:
<?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.