ThinkPHP5生成二维码图片与另一张背景图片进行合成

1、PHP方法

 1 public function do_qrcode(){       
 2         Vendor('Qrcode.phpqrcode');
 3         Vendor('Qrcode.Compress');
 4         $object = new \QRcode();
 5         $recommend = $user['invite'];
 6         //二维码跳转地址
 7         $url = config('public.qrcode')."?recommend=".$recommend;
 8         //需要合成的背景图片地址
 9         $bgimg = config('public.host').config('public.static').'/bj.jpg';       
10         $host = config('public.host');
11         $path = "./public/qrcode/".$recommend.".jpg";
12         $r_path =  "/public/qrcode/".$recommend.".jpg";
13         if(!file_exists('./public/qrcode/')){
14             mkdir('./public/qrcode/',0777,true);
15         }
16         $level=3;
17         $size=5;
18         $errorCorrectionLevel =intval($level) ;
19         $matrixPointSize = intval($size);
20         $object->png($url, $path, $errorCorrectionLevel, $matrixPointSize, 2); 
21         //生成的二维码图片地址
22         $img = $host.'/'.$r_path;        
23         /* 图片合成开始 */
24         $bigImg = imagecreatefromstring(file_get_contents($bgimg));
25         $qCodeImg = imagecreatefromstring(file_get_contents($img));
26         list($qCodeWidth, $qCodeHight, $qCodeType) = getimagesize($img); 
27         imagecopymerge($bigImg, $qCodeImg, 260, 780, 0, 0, $qCodeWidth, $qCodeHight, 100);
28         list($bigWidth, $bigHight, $bigType) = getimagesize($bgimg);
29         imagejpeg($bigImg,"./public/qrcode/".$recommend.".jpg");
30         /* 图片合成结束 */
31         $source = "./public/qrcode/".$recommend.".jpg";
32         $dst_img = "./public/qrcode/".$recommend.".jpg";
33         $percent = 0.5;  #原图压缩,不缩放
34         $image = (new \Compress($source,$percent))->compressImg($dst_img);        
35         //合成后的图片地址
36         $img = $host."/public/qrcode/".$recommend.".jpg";
37         $json = [
38             'code' => config('code.success'),
39             'msg' => '获取成功',
40             'res' => 'success',
41             'img' => $img
42         ];
43         echo json_encode($json);
44         exit;
45     }

2、Compress.php

  1 <?php
  2 class Compress
  3 {
  4     private $src;
  5     private $image;
  6     private $imageinfo;
  7     private $percent=0.5;
  8     
  9     /*
 10     param    $src源图
 11     param    $percent压缩比例
 12     */
 13     public function __construct($src,$percent=1)
 14     {
 15         $this->src = $src;
 16         $this->percent = $percent;
 17     }
 18        
 19     /*
 20     param string $saveName 图片名(可不带扩展名用原图名)用于保存。或不提供文件名直接显示
 21     */
 22     public function compressImg($saveName='')
 23     {
 24         $this->_openImage();
 25         if(!empty($saveName))
 26         {
 27             $this->_saveImage($saveName);//保存
 28         }
 29         else
 30         {
 31             $this->_showImage();
 32         }
 33     }
 34 
 35     /*
 36     内部:打开图片
 37     */
 38     private function _openImage()
 39     {
 40         list($width, $height, $type, $attr) = getimagesize($this->src);
 41         $this->imageinfo = array(
 42             'width'=>$width,
 43             'height'=>$height,
 44             'type'=>image_type_to_extension($type,false),
 45             'attr'=>$attr
 46           );
 47         $fun = "imagecreatefrom".$this->imageinfo['type'];
 48         $this->image = $fun($this->src);
 49         $this->_thumpImage();
 50     }
 51 
 52     /**
 53     * 内部:操作图片
 54     */
 55     private function _thumpImage()
 56     {
 57         $new_width = $this->imageinfo['width'] * $this->percent;
 58         $new_height = $this->imageinfo['height'] * $this->percent;
 59         $image_thump = imagecreatetruecolor($new_width,$new_height);
 60         //将原图复制带图片载体上面,并且按照一定比例压缩,极大的保持了清晰度
 61         imagecopyresampled($image_thump,$this->image,0,0,0,0,$new_width,$new_height,$this->imageinfo['width'],$this->imageinfo['height']);
 62         imagedestroy($this->image);
 63         $this->image = $image_thump;
 64     }
 65 
 66     /**
 67     * 输出图片:保存图片则用saveImage()
 68     */
 69     private function _showImage()
 70     {
 71         header('Content-Type: image/'.$this->imageinfo['type']);
 72         $funcs = "image".$this->imageinfo['type'];
 73         $funcs($this->image);
 74     }
 75 
 76     /**
 77     * 保存图片到硬盘:
 78     * @param  string $dstImgName  1、可指定字符串不带后缀的名称,使用源图扩展名 。2、直接指定目标图片名带扩展名。
 79     */
 80     private function _saveImage($dstImgName)
 81     {
 82         if(empty($dstImgName)) return false;
 83         $allowImgs = ['.jpg', '.jpeg', '.png', '.bmp', '.wbmp','.gif'];   //如果目标图片名有后缀就用目标图片扩展名 后缀,如果没有,则用源图的扩展名
 84         $dstExt =  strrchr($dstImgName ,".");
 85         $sourseExt = strrchr($this->src ,".");
 86         if(!empty($dstExt)) $dstExt =strtolower($dstExt);
 87         if(!empty($sourseExt)) $sourseExt =strtolower($sourseExt);
 88      
 89         //有指定目标名扩展名
 90         if(!empty($dstExt) && in_array($dstExt,$allowImgs))
 91         {
 92             $dstName = $dstImgName;
 93         }
 94         elseif(!empty($sourseExt) && in_array($sourseExt,$allowImgs))
 95         {
 96             $dstName = $dstImgName.$sourseExt;
 97         }
 98         else
 99         {
100             $dstName = $dstImgName.$this->imageinfo['type'];
101         }
102         $funcs = "image".$this->imageinfo['type'];
103         $funcs($this->image,$dstName);
104     }
105 
106     /**
107     * 销毁图片
108     */
109     public function __destruct()
110     {
111        imagedestroy($this->image);
112     }
113 }

3、phpqrcode.php

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

 

posted @ 2020-05-02 13:28  糖糖Y  阅读(982)  评论(0编辑  收藏  举报