survey_seahorse

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

qrmask.php (12584B)


      1 <?php
      2 /*
      3  * PHP QR Code encoder
      4  *
      5  * Masking
      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 	define('N1', 3);
     29 	define('N2', 3);
     30 	define('N3', 40);
     31 	define('N4', 10);
     32 
     33 	class QRmask {
     34 	
     35 		public $runLength = array();
     36 		
     37 		//----------------------------------------------------------------------
     38 		public function __construct() 
     39         {
     40             $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
     41         }
     42         
     43         //----------------------------------------------------------------------
     44         public function writeFormatInformation($width, &$frame, $mask, $level)
     45         {
     46             $blacks = 0;
     47             $format =  QRspec::getFormatInfo($mask, $level);
     48 
     49             for($i=0; $i<8; $i++) {
     50                 if($format & 1) {
     51                     $blacks += 2;
     52                     $v = 0x85;
     53                 } else {
     54                     $v = 0x84;
     55                 }
     56                 
     57                 $frame[8][$width - 1 - $i] = chr($v);
     58                 if($i < 6) {
     59                     $frame[$i][8] = chr($v);
     60                 } else {
     61                     $frame[$i + 1][8] = chr($v);
     62                 }
     63                 $format = $format >> 1;
     64             }
     65             
     66             for($i=0; $i<7; $i++) {
     67                 if($format & 1) {
     68                     $blacks += 2;
     69                     $v = 0x85;
     70                 } else {
     71                     $v = 0x84;
     72                 }
     73                 
     74                 $frame[$width - 7 + $i][8] = chr($v);
     75                 if($i == 0) {
     76                     $frame[8][7] = chr($v);
     77                 } else {
     78                     $frame[8][6 - $i] = chr($v);
     79                 }
     80                 
     81                 $format = $format >> 1;
     82             }
     83 
     84             return $blacks;
     85         }
     86         
     87         //----------------------------------------------------------------------
     88         public function mask0($x, $y) { return ($x+$y)&1;                       }
     89         public function mask1($x, $y) { return ($y&1);                          }
     90         public function mask2($x, $y) { return ($x%3);                          }
     91         public function mask3($x, $y) { return ($x+$y)%3;                       }
     92         public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }
     93         public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3;           }
     94         public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1;       }
     95         public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1;     }
     96         
     97         //----------------------------------------------------------------------
     98         private function generateMaskNo($maskNo, $width, $frame)
     99         {
    100             $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
    101             
    102             for($y=0; $y<$width; $y++) {
    103                 for($x=0; $x<$width; $x++) {
    104                     if(ord($frame[$y][$x]) & 0x80) {
    105                         $bitMask[$y][$x] = 0;
    106                     } else {
    107                         $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
    108                         $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
    109                     }
    110                     
    111                 }
    112             }
    113             
    114             return $bitMask;
    115         }
    116         
    117         //----------------------------------------------------------------------
    118         public static function serial($bitFrame)
    119         {
    120             $codeArr = array();
    121             
    122             foreach ($bitFrame as $line)
    123                 $codeArr[] = join('', $line);
    124                 
    125             return gzcompress(join("\n", $codeArr), 9);
    126         }
    127         
    128         //----------------------------------------------------------------------
    129         public static function unserial($code)
    130         {
    131             $codeArr = array();
    132             
    133             $codeLines = explode("\n", gzuncompress($code));
    134             foreach ($codeLines as $line)
    135                 $codeArr[] = str_split($line);
    136             
    137             return $codeArr;
    138         }
    139         
    140         //----------------------------------------------------------------------
    141         public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) 
    142         {
    143             $b = 0;
    144             $bitMask = array();
    145             
    146             $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
    147 
    148             if (QR_CACHEABLE) {
    149                 if (file_exists($fileName)) {
    150                     $bitMask = self::unserial(file_get_contents($fileName));
    151                 } else {
    152                     $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
    153                     if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
    154                         mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
    155                     file_put_contents($fileName, self::serial($bitMask));
    156                 }
    157             } else {
    158                 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
    159             }
    160 
    161             if ($maskGenOnly)
    162                 return;
    163                 
    164             $d = $s;
    165 
    166             for($y=0; $y<$width; $y++) {
    167                 for($x=0; $x<$width; $x++) {
    168                     if($bitMask[$y][$x] == 1) {
    169                         $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
    170                     }
    171                     $b += (int)(ord($d[$y][$x]) & 1);
    172                 }
    173             }
    174 
    175             return $b;
    176         }
    177         
    178         //----------------------------------------------------------------------
    179         public function makeMask($width, $frame, $maskNo, $level)
    180         {
    181             $masked = array_fill(0, $width, str_repeat("\0", $width));
    182             $this->makeMaskNo($maskNo, $width, $frame, $masked);
    183             $this->writeFormatInformation($width, $masked, $maskNo, $level);
    184        
    185             return $masked;
    186         }
    187         
    188         //----------------------------------------------------------------------
    189         public function calcN1N3($length)
    190         {
    191             $demerit = 0;
    192 
    193             for($i=0; $i<$length; $i++) {
    194                 
    195                 if($this->runLength[$i] >= 5) {
    196                     $demerit += (N1 + ($this->runLength[$i] - 5));
    197                 }
    198                 if($i & 1) {
    199                     if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {
    200                         $fact = (int)($this->runLength[$i] / 3);
    201                         if(($this->runLength[$i-2] == $fact) &&
    202                            ($this->runLength[$i-1] == $fact) &&
    203                            ($this->runLength[$i+1] == $fact) &&
    204                            ($this->runLength[$i+2] == $fact)) {
    205                             if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {
    206                                 $demerit += N3;
    207                             } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {
    208                                 $demerit += N3;
    209                             }
    210                         }
    211                     }
    212                 }
    213             }
    214             return $demerit;
    215         }
    216         
    217         //----------------------------------------------------------------------
    218         public function evaluateSymbol($width, $frame)
    219         {
    220             $head = 0;
    221             $demerit = 0;
    222 
    223             for($y=0; $y<$width; $y++) {
    224                 $head = 0;
    225                 $this->runLength[0] = 1;
    226                 
    227                 $frameY = $frame[$y];
    228                 
    229                 if ($y>0)
    230                     $frameYM = $frame[$y-1];
    231                 
    232                 for($x=0; $x<$width; $x++) {
    233                     if(($x > 0) && ($y > 0)) {
    234                         $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
    235                         $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
    236                         
    237                         if(($b22 | ($w22 ^ 1))&1) {                                                                     
    238                             $demerit += N2;
    239                         }
    240                     }
    241                     if(($x == 0) && (ord($frameY[$x]) & 1)) {
    242                         $this->runLength[0] = -1;
    243                         $head = 1;
    244                         $this->runLength[$head] = 1;
    245                     } else if($x > 0) {
    246                         if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
    247                             $head++;
    248                             $this->runLength[$head] = 1;
    249                         } else {
    250                             $this->runLength[$head]++;
    251                         }
    252                     }
    253                 }
    254     
    255                 $demerit += $this->calcN1N3($head+1);
    256             }
    257 
    258             for($x=0; $x<$width; $x++) {
    259                 $head = 0;
    260                 $this->runLength[0] = 1;
    261                 
    262                 for($y=0; $y<$width; $y++) {
    263                     if($y == 0 && (ord($frame[$y][$x]) & 1)) {
    264                         $this->runLength[0] = -1;
    265                         $head = 1;
    266                         $this->runLength[$head] = 1;
    267                     } else if($y > 0) {
    268                         if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
    269                             $head++;
    270                             $this->runLength[$head] = 1;
    271                         } else {
    272                             $this->runLength[$head]++;
    273                         }
    274                     }
    275                 }
    276             
    277                 $demerit += $this->calcN1N3($head+1);
    278             }
    279 
    280             return $demerit;
    281         }
    282         
    283         
    284         //----------------------------------------------------------------------
    285         public function mask($width, $frame, $level)
    286         {
    287             $minDemerit = PHP_INT_MAX;
    288             $bestMaskNum = 0;
    289             $bestMask = array();
    290             
    291             $checked_masks = array(0,1,2,3,4,5,6,7);
    292             
    293             if (QR_FIND_FROM_RANDOM !== false) {
    294             
    295                 $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);
    296                 for ($i = 0; $i <  $howManuOut; $i++) {
    297                     $remPos = rand (0, count($checked_masks)-1);
    298                     unset($checked_masks[$remPos]);
    299                     $checked_masks = array_values($checked_masks);
    300                 }
    301             
    302             }
    303             
    304             $bestMask = $frame;
    305              
    306             foreach($checked_masks as $i) {
    307                 $mask = array_fill(0, $width, str_repeat("\0", $width));
    308 
    309                 $demerit = 0;
    310                 $blacks = 0;
    311                 $blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
    312                 $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
    313                 $blacks  = (int)(100 * $blacks / ($width * $width));
    314                 $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
    315                 $demerit += $this->evaluateSymbol($width, $mask);
    316                 
    317                 if($demerit < $minDemerit) {
    318                     $minDemerit = $demerit;
    319                     $bestMask = $mask;
    320                     $bestMaskNum = $i;
    321                 }
    322             }
    323             
    324             return $bestMask;
    325         }
    326         
    327         //----------------------------------------------------------------------
    328     }