• 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                 "xa1xa1xa1xa1xa1",
     596                 "xa1xa0xa0xa0xa1",
     597                 "xa1xa0xa1xa0xa1",
     598                 "xa1xa0xa0xa0xa1",
     599                 "xa1xa1xa1xa1xa1"
     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                 "xc1xc1xc1xc1xc1xc1xc1",
     708                 "xc1xc0xc0xc0xc0xc0xc1",
     709                 "xc1xc0xc1xc1xc1xc0xc1",
     710                 "xc1xc0xc1xc1xc1xc0xc1",
     711                 "xc1xc0xc1xc1xc1xc0xc1",
     712                 "xc1xc0xc0xc0xc0xc0xc1",
     713                 "xc1xc1xc1xc1xc1xc1xc1"
     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 ("", $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("", $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("
    ", $frame), 9);
     857         }
     858         
     859         //----------------------------------------------------------------------
     860         public static function unserial($code)
     861         {
     862             return explode("
    ", 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 == '' || $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("
    ", $codeArr), 9);
    2598         }
    2599         
    2600         //----------------------------------------------------------------------
    2601         public static function unserial($code)
    2602         {
    2603             $codeArr = array();
    2604             
    2605             $codeLines = explode("
    ", 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("", $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("", $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("
    ", 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
  • 相关阅读:
    共望明月
    游丽都公园有感
    创业天才尼尔曼迈向成功的十四个原则
    赵娜(帮别人名字作诗)
    小幽默也有大道理:哲理幽默15则
    夜游草堂
    成功就是简单的事情重复做、重复做
    千万别入错行 15条人生建议
    听一堂课值三十九万,把它看完,定会有收获!
    VIEW:X$KCCRSControlfile Record Section directory (8.0 8.1)
  • 原文地址:https://www.cnblogs.com/Jessie-candy/p/12817830.html
Copyright © 2020-2023  润新知