survey_seahorse

Software Engineering Project - Fall 2018
Log | Files | Refs | README

qrencode.php (17506B)


      1 <?php
      2 /*
      3  * PHP QR Code encoder
      4  *
      5  * Main encoder classes.
      6  *
      7  * Based on libqrencode C library distributed under LGPL 2.1
      8  * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
      9  *
     10  * PHP QR Code is distributed under LGPL 3
     11  * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
     12  *
     13  * This library is free software; you can redistribute it and/or
     14  * modify it under the terms of the GNU Lesser General Public
     15  * License as published by the Free Software Foundation; either
     16  * version 3 of the License, or any later version.
     17  *
     18  * This library is distributed in the hope that it will be useful,
     19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     21  * Lesser General Public License for more details.
     22  *
     23  * You should have received a copy of the GNU Lesser General Public
     24  * License along with this library; if not, write to the Free Software
     25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
     26  */
     27  
     28     class QRrsblock {
     29         public $dataLength;
     30         public $data = array();
     31         public $eccLength;
     32         public $ecc = array();
     33         
     34         public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
     35         {
     36             $rs->encode_rs_char($data, $ecc);
     37         
     38             $this->dataLength = $dl;
     39             $this->data = $data;
     40             $this->eccLength = $el;
     41             $this->ecc = $ecc;
     42         }
     43     };
     44     
     45     //##########################################################################
     46 
     47     class QRrawcode {
     48         public $version;
     49         public $datacode = array();
     50         public $ecccode = array();
     51         public $blocks;
     52         public $rsblocks = array(); //of RSblock
     53         public $count;
     54         public $dataLength;
     55         public $eccLength;
     56         public $b1;
     57         
     58         //----------------------------------------------------------------------
     59         public function __construct(QRinput $input)
     60         {
     61             $spec = array(0,0,0,0,0);
     62             
     63             $this->datacode = $input->getByteStream();
     64             if(is_null($this->datacode)) {
     65                 throw new Exception('null imput string');
     66             }
     67 
     68             QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
     69 
     70             $this->version = $input->getVersion();
     71             $this->b1 = QRspec::rsBlockNum1($spec);
     72             $this->dataLength = QRspec::rsDataLength($spec);
     73             $this->eccLength = QRspec::rsEccLength($spec);
     74             $this->ecccode = array_fill(0, $this->eccLength, 0);
     75             $this->blocks = QRspec::rsBlockNum($spec);
     76             
     77             $ret = $this->init($spec);
     78             if($ret < 0) {
     79                 throw new Exception('block alloc error');
     80                 return null;
     81             }
     82 
     83             $this->count = 0;
     84         }
     85         
     86         //----------------------------------------------------------------------
     87         public function init(array $spec)
     88         {
     89             $dl = QRspec::rsDataCodes1($spec);
     90             $el = QRspec::rsEccCodes1($spec);
     91             $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
     92             
     93 
     94             $blockNo = 0;
     95             $dataPos = 0;
     96             $eccPos = 0;
     97             for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {
     98                 $ecc = array_slice($this->ecccode,$eccPos);
     99                 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el,  $ecc, $rs);
    100                 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
    101                 
    102                 $dataPos += $dl;
    103                 $eccPos += $el;
    104                 $blockNo++;
    105             }
    106 
    107             if(QRspec::rsBlockNum2($spec) == 0)
    108                 return 0;
    109 
    110             $dl = QRspec::rsDataCodes2($spec);
    111             $el = QRspec::rsEccCodes2($spec);
    112             $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
    113             
    114             if($rs == NULL) return -1;
    115             
    116             for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {
    117                 $ecc = array_slice($this->ecccode,$eccPos);
    118                 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
    119                 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
    120                 
    121                 $dataPos += $dl;
    122                 $eccPos += $el;
    123                 $blockNo++;
    124             }
    125 
    126             return 0;
    127         }
    128         
    129         //----------------------------------------------------------------------
    130         public function getCode()
    131         {
    132             $ret;
    133 
    134             if($this->count < $this->dataLength) {
    135                 $row = $this->count % $this->blocks;
    136                 $col = $this->count / $this->blocks;
    137                 if($col >= $this->rsblocks[0]->dataLength) {
    138                     $row += $this->b1;
    139                 }
    140                 $ret = $this->rsblocks[$row]->data[$col];
    141             } else if($this->count < $this->dataLength + $this->eccLength) {
    142                 $row = ($this->count - $this->dataLength) % $this->blocks;
    143                 $col = ($this->count - $this->dataLength) / $this->blocks;
    144                 $ret = $this->rsblocks[$row]->ecc[$col];
    145             } else {
    146                 return 0;
    147             }
    148             $this->count++;
    149             
    150             return $ret;
    151         }
    152     }
    153 
    154     //##########################################################################
    155     
    156     class QRcode {
    157     
    158         public $version;
    159         public $width;
    160         public $data; 
    161         
    162         //----------------------------------------------------------------------
    163         public function encodeMask(QRinput $input, $mask)
    164         {
    165             if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
    166                 throw new Exception('wrong version');
    167             }
    168             if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
    169                 throw new Exception('wrong level');
    170             }
    171 
    172             $raw = new QRrawcode($input);
    173             
    174             QRtools::markTime('after_raw');
    175             
    176             $version = $raw->version;
    177             $width = QRspec::getWidth($version);
    178             $frame = QRspec::newFrame($version);
    179             
    180             $filler = new FrameFiller($width, $frame);
    181             if(is_null($filler)) {
    182                 return NULL;
    183             }
    184 
    185             // inteleaved data and ecc codes
    186             for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
    187                 $code = $raw->getCode();
    188                 $bit = 0x80;
    189                 for($j=0; $j<8; $j++) {
    190                     $addr = $filler->next();
    191                     $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
    192                     $bit = $bit >> 1;
    193                 }
    194             }
    195             
    196             QRtools::markTime('after_filler');
    197             
    198             unset($raw);
    199             
    200             // remainder bits
    201             $j = QRspec::getRemainder($version);
    202             for($i=0; $i<$j; $i++) {
    203                 $addr = $filler->next();
    204                 $filler->setFrameAt($addr, 0x02);
    205             }
    206             
    207             $frame = $filler->frame;
    208             unset($filler);
    209             
    210             
    211             // masking
    212             $maskObj = new QRmask();
    213             if($mask < 0) {
    214             
    215                 if (QR_FIND_BEST_MASK) {
    216                     $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
    217                 } else {
    218                     $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
    219                 }
    220             } else {
    221                 $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
    222             }
    223             
    224             if($masked == NULL) {
    225                 return NULL;
    226             }
    227             
    228             QRtools::markTime('after_mask');
    229             
    230             $this->version = $version;
    231             $this->width = $width;
    232             $this->data = $masked;
    233             
    234             return $this;
    235         }
    236     
    237         //----------------------------------------------------------------------
    238         public function encodeInput(QRinput $input)
    239         {
    240             return $this->encodeMask($input, -1);
    241         }
    242         
    243         //----------------------------------------------------------------------
    244         public function encodeString8bit($string, $version, $level)
    245         {
    246             if(string == NULL) {
    247                 throw new Exception('empty string!');
    248                 return NULL;
    249             }
    250 
    251             $input = new QRinput($version, $level);
    252             if($input == NULL) return NULL;
    253 
    254             $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));
    255             if($ret < 0) {
    256                 unset($input);
    257                 return NULL;
    258             }
    259             return $this->encodeInput($input);
    260         }
    261 
    262         //----------------------------------------------------------------------
    263         public function encodeString($string, $version, $level, $hint, $casesensitive)
    264         {
    265 
    266             if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
    267                 throw new Exception('bad hint');
    268                 return NULL;
    269             }
    270 
    271             $input = new QRinput($version, $level);
    272             if($input == NULL) return NULL;
    273 
    274             $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
    275             if($ret < 0) {
    276                 return NULL;
    277             }
    278 
    279             return $this->encodeInput($input);
    280         }
    281         
    282         //----------------------------------------------------------------------
    283         public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) 
    284         {
    285             $enc = QRencode::factory($level, $size, $margin);
    286             return $enc->encodePNG($text, $outfile, $saveandprint=false);
    287         }
    288 
    289         //----------------------------------------------------------------------
    290         public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
    291         {
    292             $enc = QRencode::factory($level, $size, $margin);
    293             return $enc->encode($text, $outfile);
    294         }
    295 
    296         //----------------------------------------------------------------------
    297         public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
    298         {
    299             $enc = QRencode::factory($level, $size, $margin);
    300             return $enc->encodeRAW($text, $outfile);
    301         }
    302     }
    303     
    304     //##########################################################################
    305     
    306     class FrameFiller {
    307     
    308         public $width;
    309         public $frame;
    310         public $x;
    311         public $y;
    312         public $dir;
    313         public $bit;
    314         
    315         //----------------------------------------------------------------------
    316         public function __construct($width, &$frame)
    317         {
    318             $this->width = $width;
    319             $this->frame = $frame;
    320             $this->x = $width - 1;
    321             $this->y = $width - 1;
    322             $this->dir = -1;
    323             $this->bit = -1;
    324         }
    325         
    326         //----------------------------------------------------------------------
    327         public function setFrameAt($at, $val)
    328         {
    329             $this->frame[$at['y']][$at['x']] = chr($val);
    330         }
    331         
    332         //----------------------------------------------------------------------
    333         public function getFrameAt($at)
    334         {
    335             return ord($this->frame[$at['y']][$at['x']]);
    336         }
    337         
    338         //----------------------------------------------------------------------
    339         public function next()
    340         {
    341             do {
    342             
    343                 if($this->bit == -1) {
    344                     $this->bit = 0;
    345                     return array('x'=>$this->x, 'y'=>$this->y);
    346                 }
    347 
    348                 $x = $this->x;
    349                 $y = $this->y;
    350                 $w = $this->width;
    351 
    352                 if($this->bit == 0) {
    353                     $x--;
    354                     $this->bit++;
    355                 } else {
    356                     $x++;
    357                     $y += $this->dir;
    358                     $this->bit--;
    359                 }
    360 
    361                 if($this->dir < 0) {
    362                     if($y < 0) {
    363                         $y = 0;
    364                         $x -= 2;
    365                         $this->dir = 1;
    366                         if($x == 6) {
    367                             $x--;
    368                             $y = 9;
    369                         }
    370                     }
    371                 } else {
    372                     if($y == $w) {
    373                         $y = $w - 1;
    374                         $x -= 2;
    375                         $this->dir = -1;
    376                         if($x == 6) {
    377                             $x--;
    378                             $y -= 8;
    379                         }
    380                     }
    381                 }
    382                 if($x < 0 || $y < 0) return null;
    383 
    384                 $this->x = $x;
    385                 $this->y = $y;
    386 
    387             } while(ord($this->frame[$y][$x]) & 0x80);
    388                         
    389             return array('x'=>$x, 'y'=>$y);
    390         }
    391         
    392     } ;
    393     
    394     //##########################################################################    
    395     
    396     class QRencode {
    397     
    398         public $casesensitive = true;
    399         public $eightbit = false;
    400         
    401         public $version = 0;
    402         public $size = 3;
    403         public $margin = 4;
    404         
    405         public $structured = 0; // not supported yet
    406         
    407         public $level = QR_ECLEVEL_L;
    408         public $hint = QR_MODE_8;
    409         
    410         //----------------------------------------------------------------------
    411         public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)
    412         {
    413             $enc = new QRencode();
    414             $enc->size = $size;
    415             $enc->margin = $margin;
    416             
    417             switch ($level.'') {
    418                 case '0':
    419                 case '1':
    420                 case '2':
    421                 case '3':
    422                         $enc->level = $level;
    423                     break;
    424                 case 'l':
    425                 case 'L':
    426                         $enc->level = QR_ECLEVEL_L;
    427                     break;
    428                 case 'm':
    429                 case 'M':
    430                         $enc->level = QR_ECLEVEL_M;
    431                     break;
    432                 case 'q':
    433                 case 'Q':
    434                         $enc->level = QR_ECLEVEL_Q;
    435                     break;
    436                 case 'h':
    437                 case 'H':
    438                         $enc->level = QR_ECLEVEL_H;
    439                     break;
    440             }
    441             
    442             return $enc;
    443         }
    444         
    445         //----------------------------------------------------------------------
    446         public function encodeRAW($intext, $outfile = false) 
    447         {
    448             $code = new QRcode();
    449 
    450             if($this->eightbit) {
    451                 $code->encodeString8bit($intext, $this->version, $this->level);
    452             } else {
    453                 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
    454             }
    455             
    456             return $code->data;
    457         }
    458 
    459         //----------------------------------------------------------------------
    460         public function encode($intext, $outfile = false) 
    461         {
    462             $code = new QRcode();
    463 
    464             if($this->eightbit) {
    465                 $code->encodeString8bit($intext, $this->version, $this->level);
    466             } else {
    467                 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
    468             }
    469             
    470             QRtools::markTime('after_encode');
    471             
    472             if ($outfile!== false) {
    473                 file_put_contents($outfile, join("\n", QRtools::binarize($code->data)));
    474             } else {
    475                 return QRtools::binarize($code->data);
    476             }
    477         }
    478         
    479         //----------------------------------------------------------------------
    480         public function encodePNG($intext, $outfile = false,$saveandprint=false) 
    481         {
    482             try {
    483             
    484                 ob_start();
    485                 $tab = $this->encode($intext);
    486                 $err = ob_get_contents();
    487                 ob_end_clean();
    488                 
    489                 if ($err != '')
    490                     QRtools::log($outfile, $err);
    491                 
    492                 $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
    493                 
    494                 QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
    495             
    496             } catch (Exception $e) {
    497             
    498                 QRtools::log($outfile, $e->getMessage());
    499             
    500             }
    501         }
    502     }