| 1 |
<?php |
| 2 |
/* |
| 3 |
* Generateur de QRCode |
| 4 |
* (QR Code is registered trademark of DENSO WAVE INCORPORATED | http://www.denso-wave.com/qrcode/) |
| 5 |
* Fortement inspiré de "QRcode image PHP scripts version 0.50g (C)2000-2005,Y.Swetake" |
| 6 |
* |
| 7 |
* Distribué sous la licence LGPL. |
| 8 |
* |
| 9 |
* @author Laurent MINGUET <webmaster@spipu.net> |
| 10 |
* @version 0.99 |
| 11 |
*/ |
| 12 |
|
| 13 |
if (!defined('__CLASS_QRCODE__')) |
| 14 |
{ |
| 15 |
define('__CLASS_QRCODE__', '0.99'); |
| 16 |
|
| 17 |
class QRcode |
| 18 |
{ |
| 19 |
private $version_mx = 40; // numero de version maximal autorisé |
| 20 |
private $type = 'bin'; // type de donnée |
| 21 |
private $level = 'L'; // ECC |
| 22 |
private $value = ''; // valeur a encoder |
| 23 |
private $length = 0; // taille de la valeur |
| 24 |
private $version = 0; // version |
| 25 |
private $size = 0; // dimension de la zone data |
| 26 |
private $qr_size = 0; // dimension du QRcode |
| 27 |
|
| 28 |
private $data_bit = array(); // nb de bit de chacune des valeurs |
| 29 |
private $data_val = array(); // liste des valeurs de bit différents |
| 30 |
private $data_word = array(); // liste des valeurs tout ramené à 8bit |
| 31 |
private $data_cur = 0; // position courante |
| 32 |
private $data_num = 0; // position de la dimension |
| 33 |
private $data_bits = 0; // nom de bit au total |
| 34 |
private $max_data_bit = 0; // lilmite de nombre de bit maximal pour les datas |
| 35 |
private $max_data_word = 0; // lilmite de nombre de mot maximal pour les datas |
| 36 |
private $max_word = 0; // lilmite de nombre de mot maximal en global |
| 37 |
|
| 38 |
private $ec = 0; |
| 39 |
private $matrix = array(); |
| 40 |
private $matrix_remain = 0; |
| 41 |
private $matrix_x_array = array(); |
| 42 |
private $matrix_y_array = array(); |
| 43 |
private $mask_array = array(); |
| 44 |
private $format_information_x1 = array(); |
| 45 |
private $format_information_y1 = array(); |
| 46 |
private $format_information_x2 = array(); |
| 47 |
private $format_information_y2 = array(); |
| 48 |
private $rs_block_order = array(); |
| 49 |
private $rs_ecc_codewords = 0; |
| 50 |
private $byte_num = 0; |
| 51 |
|
| 52 |
private $final = array(); |
| 53 |
private $disable_border = false; |
| 54 |
|
| 55 |
|
| 56 |
/** |
| 57 |
* Constructeur |
| 58 |
* |
| 59 |
* @param string message a encoder |
| 60 |
* @param string niveau de correction d'erreur (ECC) : L, M, Q, H |
| 61 |
* @return null |
| 62 |
*/ |
| 63 |
public function __construct($value, $level='L') |
| 64 |
{ |
| 65 |
if (!in_array($level, array('L', 'M', 'Q', 'H'))) |
| 66 |
$this->ERROR('ECC non reconnu : L, M, Q, H'); |
| 67 |
|
| 68 |
$this->length = strlen($value); |
| 69 |
if (!$this->length) |
| 70 |
$this->ERROR('pas de data...'); |
| 71 |
|
| 72 |
$this->level = $level; |
| 73 |
$this->value = &$value; |
| 74 |
|
| 75 |
$this->data_bit = array(); |
| 76 |
$this->data_val = array(); |
| 77 |
$this->data_cur = 0; |
| 78 |
$this->data_bits= 0; |
| 79 |
|
| 80 |
$this->encode(); |
| 81 |
$this->loadECC(); |
| 82 |
$this->makeECC(); |
| 83 |
$this->makeMatrix(); |
| 84 |
} |
| 85 |
|
| 86 |
/** |
| 87 |
* permet de recuperer la taille du QRcode (le nombre de case de côté) |
| 88 |
* |
| 89 |
* @return int size of qrcode |
| 90 |
*/ |
| 91 |
public function getQrSize() |
| 92 |
{ |
| 93 |
if ($this->disable_border) |
| 94 |
return $this->qr_size-8; |
| 95 |
else |
| 96 |
return $this->qr_size; |
| 97 |
} |
| 98 |
|
| 99 |
public function disableBorder() |
| 100 |
{ |
| 101 |
$this->disable_border = true; |
| 102 |
} |
| 103 |
|
| 104 |
/** |
| 105 |
* permet d'afficher le QRcode dans un pdf via FPDF |
| 106 |
* |
| 107 |
* @param FPDF objet fpdf |
| 108 |
* @param float position X |
| 109 |
* @param float position Y |
| 110 |
* @param float taille du qrcode |
| 111 |
* @param array couleur du background (R,V,B) |
| 112 |
* @param array couleur des cases et du border (R,V,B) |
| 113 |
* @return boolean true; |
| 114 |
*/ |
| 115 |
public function displayFPDF(&$fpdf, $x, $y, $w, $background=array(255,255,255), $color=array(0,0,0)) |
| 116 |
{ |
| 117 |
$size = $w; |
| 118 |
$s = $size/$this->getQrSize(); |
| 119 |
|
| 120 |
$fpdf->SetDrawColor($color[0], $color[1], $color[2]); |
| 121 |
$fpdf->SetFillColor($background[0], $background[1], $background[2]); |
| 122 |
|
| 123 |
// rectangle de fond |
| 124 |
if ($this->disable_border) |
| 125 |
{ |
| 126 |
$s_min = 4; |
| 127 |
$s_max = $this->qr_size-4; |
| 128 |
$fpdf->Rect($x, $y, $size, $size, 'F'); |
| 129 |
} |
| 130 |
else |
| 131 |
{ |
| 132 |
$s_min = 0; |
| 133 |
$s_max = $this->qr_size; |
| 134 |
$fpdf->Rect($x, $y, $size, $size, 'FD'); |
| 135 |
} |
| 136 |
|
| 137 |
$fpdf->SetFillColor($color[0], $color[1], $color[2]); |
| 138 |
for($j=$s_min; $j<$s_max; $j++) |
| 139 |
for($i=$s_min; $i<$s_max; $i++) |
| 140 |
if ($this->final[$i + $j*$this->qr_size+1]) |
| 141 |
$fpdf->Rect($x+($i-$s_min)*$s, $y+($j-$s_min)*$s, $s, $s, 'F'); |
| 142 |
|
| 143 |
return true; |
| 144 |
} |
| 145 |
|
| 146 |
/** |
| 147 |
* permet d'afficher le QRcode au format HTML, à utiliser avec un style CSS |
| 148 |
* |
| 149 |
* @return boolean true; |
| 150 |
*/ |
| 151 |
public function displayHTML() |
| 152 |
{ |
| 153 |
if ($this->disable_border) |
| 154 |
{ |
| 155 |
$s_min = 4; |
| 156 |
$s_max = $this->qr_size-4; |
| 157 |
} |
| 158 |
else |
| 159 |
{ |
| 160 |
$s_min = 0; |
| 161 |
$s_max = $this->qr_size; |
| 162 |
} |
| 163 |
echo '<table class="qr" cellpadding="0" cellspacing="0">'."\n"; |
| 164 |
for($y=$s_min; $y<$s_max; $y++) |
| 165 |
{ |
| 166 |
echo '<tr>'; |
| 167 |
for($x=$s_min; $x<$s_max; $x++) |
| 168 |
{ |
| 169 |
echo '<td class="'.($this->final[$x + $y*$this->qr_size+1] ? 'on' : 'off').'"></td>'; |
| 170 |
} |
| 171 |
echo '</tr>'."\n"; |
| 172 |
} |
| 173 |
echo '</table>'; |
| 174 |
|
| 175 |
return true; |
| 176 |
} |
| 177 |
|
| 178 |
/* |
| 179 |
* permet d'obtenir une image PNG |
| 180 |
* |
| 181 |
* @param float taille du qrcode |
| 182 |
* @param array couleur du background (R,V,B) |
| 183 |
* @param array couleur des cases et du border (R,V,B) |
| 184 |
* @param string nom du fichier de sortie. si null : sortie directe |
| 185 |
* @param integer qualité de 0 (aucune compression) a 9 |
| 186 |
* @return boolean true; |
| 187 |
*/ |
| 188 |
public function displayPNG($w=100, $background=array(255,255,255), $color=array(0,0,0), $filename = null, $quality = 0) |
| 189 |
{ |
| 190 |
if ($this->disable_border) |
| 191 |
{ |
| 192 |
$s_min = 4; |
| 193 |
$s_max = $this->qr_size-4; |
| 194 |
} |
| 195 |
else |
| 196 |
{ |
| 197 |
$s_min = 0; |
| 198 |
$s_max = $this->qr_size; |
| 199 |
} |
| 200 |
$size = $w; |
| 201 |
$s = $size/($s_max-$s_min); |
| 202 |
|
| 203 |
// rectangle de fond |
| 204 |
$im = imagecreatetruecolor($size,$size); |
| 205 |
$c_case = imagecolorallocate($im,$color[0],$color[1],$color[2]); |
| 206 |
$c_back = imagecolorallocate($im,$background[0],$background[1],$background[2]); |
| 207 |
imagefilledrectangle($im,0,0,$size,$size,$c_back); |
| 208 |
|
| 209 |
for($j=$s_min; $j<$s_max; $j++) |
| 210 |
for($i=$s_min; $i<$s_max; $i++) |
| 211 |
if ($this->final[$i + $j*$this->qr_size+1]) |
| 212 |
imagefilledrectangle($im,($i-$s_min)*$s,($j-$s_min)*$s,($i-$s_min+1)*$s-1,($j-$s_min+1)*$s-1,$c_case); |
| 213 |
|
| 214 |
if ($filename) |
| 215 |
{ |
| 216 |
imagepng($im, $filename, $quality); |
| 217 |
} |
| 218 |
else |
| 219 |
{ |
| 220 |
header("Content-type: image/png"); |
| 221 |
imagepng($im); |
| 222 |
} |
| 223 |
imagedestroy($im); |
| 224 |
return true; |
| 225 |
} |
| 226 |
|
| 227 |
private function ERROR($msg) |
| 228 |
{ |
| 229 |
echo 'ERROR : '.$msg; |
| 230 |
exit; |
| 231 |
} |
| 232 |
|
| 233 |
private function addData($val, $bit, $next = true) |
| 234 |
{ |
| 235 |
$this->data_val[$this->data_cur] = $val; |
| 236 |
$this->data_bit[$this->data_cur] = $bit; |
| 237 |
if ($next) |
| 238 |
{ |
| 239 |
$this->data_cur++; |
| 240 |
return $this->data_cur-1; |
| 241 |
} |
| 242 |
else |
| 243 |
{ |
| 244 |
return $this->data_cur; |
| 245 |
} |
| 246 |
} |
| 247 |
|
| 248 |
private function encode() |
| 249 |
{ |
| 250 |
// conversion des datas |
| 251 |
if (preg_match('/[^0-9]/',$this->value)) |
| 252 |
{ |
| 253 |
if (preg_match('/[^0-9A-Z \$\*\%\+\-\.\/\:]/',$this->value)) |
| 254 |
{ |
| 255 |
// type : bin |
| 256 |
$this->type = 'bin'; |
| 257 |
$this->addData(4, 4); |
| 258 |
|
| 259 |
// taille. il faut garder l'indice, car besoin de correction |
| 260 |
$this->data_num = $this->addData($this->length, 8); /* #version 1-9 */ |
| 261 |
$data_num_correction=array(0,0,0,0,0,0,0,0,0,0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8); |
| 262 |
|
| 263 |
// datas |
| 264 |
for ($i=0; $i<$this->length; $i++) |
| 265 |
$this->addData(ord(substr($this->value, $i, 1)), 8); |
| 266 |
} |
| 267 |
else |
| 268 |
{ |
| 269 |
// type : alphanum |
| 270 |
$this->type = 'alphanum'; |
| 271 |
$this->addData(2, 4); |
| 272 |
|
| 273 |
// taille. il faut garder l'indice, car besoin de correction |
| 274 |
$this->data_num = $this->addData($this->length, 9); /* #version 1-9 */ |
| 275 |
$data_num_correction=array(0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4); |
| 276 |
|
| 277 |
// datas |
| 278 |
$an_hash=array( |
| 279 |
'0'=>0,'1'=>1,'2'=>2,'3'=>3,'4'=>4,'5'=>5,'6'=>6,'7'=>7,'8'=>8,'9'=>9, |
| 280 |
'A'=>10,'B'=>11,'C'=>12,'D'=>13,'E'=>14,'F'=>15,'G'=>16,'H'=>17,'I'=>18,'J'=>19,'K'=>20,'L'=>21,'M'=>22, |
| 281 |
'N'=>23,'O'=>24,'P'=>25,'Q'=>26,'R'=>27,'S'=>28,'T'=>29,'U'=>30,'V'=>31,'W'=>32,'X'=>33,'Y'=>34,'Z'=>35, |
| 282 |
' '=>36,'$'=>37,'%'=>38,'*'=>39,'+'=>40,'-'=>41,'.'=>42,'/'=>43,':'=>44); |
| 283 |
|
| 284 |
for ($i=0; $i<$this->length; $i++) |
| 285 |
{ |
| 286 |
if (($i %2)==0) |
| 287 |
$this->addData($an_hash[substr($this->value,$i,1)], 6, false); |
| 288 |
else |
| 289 |
$this->addData($this->data_val[$this->data_cur]*45+$an_hash[substr($this->value,$i,1)], 11, true); |
| 290 |
} |
| 291 |
unset($an_hash); |
| 292 |
|
| 293 |
if (isset($this->data_bit[$this->data_cur])) |
| 294 |
$this->data_cur++; |
| 295 |
} |
| 296 |
} |
| 297 |
else |
| 298 |
{ |
| 299 |
// type : num |
| 300 |
$this->type = 'num'; |
| 301 |
$this->addData(1, 4); |
| 302 |
|
| 303 |
//taille. il faut garder l'indice, car besoin de correction |
| 304 |
$this->data_num = $this->addData($this->length, 10); /* #version 1-9 */ |
| 305 |
$data_num_correction=array(0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4); |
| 306 |
|
| 307 |
// datas |
| 308 |
for ($i=0; $i<$this->length; $i++) |
| 309 |
{ |
| 310 |
if (($i % 3)==0) |
| 311 |
$this->addData(substr($this->value,$i,1), 4, false); |
| 312 |
else if (($i % 3)==1) |
| 313 |
$this->addData($this->data_val[$this->data_cur]*10+substr($this->value,$i,1), 7, false); |
| 314 |
else |
| 315 |
$this->addData($this->data_val[$this->data_cur]*10+substr($this->value,$i,1), 10); |
| 316 |
} |
| 317 |
|
| 318 |
if (isset($this->data_bit[$this->data_cur])) |
| 319 |
$this->data_cur++; |
| 320 |
|
| 321 |
|
| 322 |
} |
| 323 |
|
| 324 |
// calcul du nombre de bits |
| 325 |
$this->data_bits=0; |
| 326 |
foreach($this->data_bit as $bit) |
| 327 |
$this->data_bits+= $bit; |
| 328 |
|
| 329 |
// code ECC |
| 330 |
$ec_hash = array('L'=>1, 'M'=>0, 'Q'=>3, 'H'=>2); |
| 331 |
$this->ec = $ec_hash[$this->level]; |
| 332 |
|
| 333 |
// tableau de taille limite de bits |
| 334 |
$max_bits = array( |
| 335 |
0,128,224,352,512,688,864,992,1232,1456,1728,2032,2320,2672,2920,3320,3624,4056,4504,5016,5352, |
| 336 |
5712,6256,6880,7312,8000,8496,9024,9544,10136,10984,11640,12328,13048,13800,14496,15312,15936,16816,17728,18672, |
| 337 |
|
| 338 |
152,272,440,640,864,1088,1248,1552,1856,2192,2592,2960,3424,3688,4184,4712,5176,5768,6360,6888, |
| 339 |
7456,8048,8752,9392,10208,10960,11744,12248,13048,13880,14744,15640,16568,17528,18448,19472,20528,21616,22496,23648, |
| 340 |
|
| 341 |
72,128,208,288,368,480,528,688,800,976,1120,1264,1440,1576,1784,2024,2264,2504,2728,3080, |
| 342 |
3248,3536,3712,4112,4304,4768,5024,5288,5608,5960,6344,6760,7208,7688,7888,8432,8768,9136,9776,10208, |
| 343 |
|
| 344 |
104,176,272,384,496,608,704,880,1056,1232,1440,1648,1952,2088,2360,2600,2936,3176,3560,3880, |
| 345 |
4096,4544,4912,5312,5744,6032,6464,6968,7288,7880,8264,8920,9368,9848,10288,10832,11408,12016,12656,13328 |
| 346 |
); |
| 347 |
|
| 348 |
// determination automatique de la version necessaire |
| 349 |
$this->version=1; |
| 350 |
$i=1+40*$this->ec; |
| 351 |
$j=$i+39; |
| 352 |
while ($i<=$j) |
| 353 |
{ |
| 354 |
if ($max_bits[$i]>=$this->data_bits+$data_num_correction[$this->version]) |
| 355 |
{ |
| 356 |
$this->max_data_bit=$max_bits[$i]; |
| 357 |
break; |
| 358 |
} |
| 359 |
$i++; |
| 360 |
$this->version++; |
| 361 |
} |
| 362 |
|
| 363 |
// verification max version |
| 364 |
if ($this->version>$this->version_mx) |
| 365 |
$this->ERROR('too large version.'); |
| 366 |
|
| 367 |
// correctif sur le nombre de bits du strlen de la valeur |
| 368 |
$this->data_bits+=$data_num_correction[$this->version]; |
| 369 |
$this->data_bit[$this->data_num]+=$data_num_correction[$this->version]; |
| 370 |
$this->max_data_word = ($this->max_data_bit/8); |
| 371 |
|
| 372 |
// nombre de mots maximal |
| 373 |
$max_words_array=array(0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156, |
| 374 |
1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706); |
| 375 |
$this->max_word = $max_words_array[$this->version]; |
| 376 |
$this->size = 17 + 4*$this->version; |
| 377 |
|
| 378 |
// nettoyages divers |
| 379 |
unset($max_bits); |
| 380 |
unset($data_num_correction); |
| 381 |
unset($max_words_array); |
| 382 |
unset($ec_hash); |
| 383 |
|
| 384 |
// terminator |
| 385 |
if ($this->data_bits<=$this->max_data_bit-4) |
| 386 |
$this->addData(0, 4); |
| 387 |
elseif ($this->data_bits<$this->max_data_bit) |
| 388 |
$this->addData(0, $this->max_data_bit-$this->data_bits); |
| 389 |
elseif ($this->data_bits>$this->max_data_bit) |
| 390 |
$this->ERROR('Overflow error'); |
| 391 |
|
| 392 |
// construction des mots de 8 bit |
| 393 |
$this->data_word = array(); |
| 394 |
$this->data_word[0] = 0; |
| 395 |
$nb_word = 0; |
| 396 |
|
| 397 |
$remaining_bit=8; |
| 398 |
for($i=0; $i<$this->data_cur; $i++) |
| 399 |
{ |
| 400 |
$buffer_val=$this->data_val[$i]; |
| 401 |
$buffer_bit=$this->data_bit[$i]; |
| 402 |
|
| 403 |
$flag = true; |
| 404 |
while ($flag) |
| 405 |
{ |
| 406 |
if ($remaining_bit>$buffer_bit) |
| 407 |
{ |
| 408 |
$this->data_word[$nb_word]=((@$this->data_word[$nb_word]<<$buffer_bit) | $buffer_val); |
| 409 |
$remaining_bit-=$buffer_bit; |
| 410 |
$flag=false; |
| 411 |
} |
| 412 |
else |
| 413 |
{ |
| 414 |
$buffer_bit-=$remaining_bit; |
| 415 |
$this->data_word[$nb_word]=((@$this->data_word[$nb_word] << $remaining_bit) | ($buffer_val >> $buffer_bit)); |
| 416 |
$nb_word++; |
| 417 |
|
| 418 |
if ($buffer_bit==0) |
| 419 |
$flag=false; |
| 420 |
else |
| 421 |
$buffer_val= ($buffer_val & ((1 << $buffer_bit)-1) ); |
| 422 |
|
| 423 |
if ($nb_word<$this->max_data_word-1) |
| 424 |
$this->data_word[$nb_word]=0; |
| 425 |
$remaining_bit=8; |
| 426 |
} |
| 427 |
} |
| 428 |
} |
| 429 |
|
| 430 |
// completion du dernier mot si incomplet |
| 431 |
if ($remaining_bit<8) |
| 432 |
$this->data_word[$nb_word]=$this->data_word[$nb_word] << $remaining_bit; |
| 433 |
else |
| 434 |
$nb_word--; |
| 435 |
|
| 436 |
// remplissage du reste |
| 437 |
if ($nb_word<$this->max_data_word-1) |
| 438 |
{ |
| 439 |
$flag=true; |
| 440 |
while ($nb_word<$this->max_data_word-1) |
| 441 |
{ |
| 442 |
$nb_word++; |
| 443 |
if ($flag) |
| 444 |
$this->data_word[$nb_word]=236; |
| 445 |
else |
| 446 |
$this->data_word[$nb_word]=17; |
| 447 |
$flag=!$flag; |
| 448 |
} |
| 449 |
} |
| 450 |
} |
| 451 |
|
| 452 |
private function loadECC() |
| 453 |
{ |
| 454 |
$matrix_remain_bit=array(0,0,7,7,7,7,7,0,0,0,0,0,0,0,3,3,3,3,3,3,3,4,4,4,4,4,4,4,3,3,3,3,3,3,3,0,0,0,0,0,0); |
| 455 |
$this->matrix_remain = $matrix_remain_bit[$this->version]; |
| 456 |
unset($matrix_remain_bit); |
| 457 |
|
| 458 |
// lecture du fichier : data file of geometry & mask for version V ,ecc level N |
| 459 |
$this->byte_num = $this->matrix_remain+ 8*$this->max_word; |
| 460 |
$filename = dirname(__FILE__)."/data/qrv".$this->version."_".$this->ec.".dat"; |
| 461 |
$fp1 = fopen ($filename, "rb"); |
| 462 |
$this->matrix_x_array = unpack("C*", fread($fp1,$this->byte_num)); |
| 463 |
$this->matrix_y_array = unpack("C*", fread($fp1,$this->byte_num)); |
| 464 |
$this->mask_array = unpack("C*", fread($fp1,$this->byte_num)); |
| 465 |
$this->format_information_x2 = unpack("C*", fread($fp1,15)); |
| 466 |
$this->format_information_y2 = unpack("C*", fread($fp1,15)); |
| 467 |
$this->rs_ecc_codewords = ord(fread($fp1,1)); |
| 468 |
$this->rs_block_order = unpack("C*", fread($fp1,128)); |
| 469 |
fclose($fp1); |
| 470 |
$this->format_information_x1 = array(0,1,2,3,4,5,7,8,8,8,8,8,8,8,8); |
| 471 |
$this->format_information_y1 = array(8,8,8,8,8,8,8,8,7,5,4,3,2,1,0); |
| 472 |
|
| 473 |
} |
| 474 |
|
| 475 |
private function makeECC() |
| 476 |
{ |
| 477 |
// lecture du fichier : data file of caluclatin tables for RS encoding |
| 478 |
$rs_cal_table_array = array(); |
| 479 |
$filename = dirname(__FILE__)."/data/rsc".$this->rs_ecc_codewords.".dat"; |
| 480 |
$fp0 = fopen ($filename, "rb"); |
| 481 |
for($i=0; $i<256; $i++) |
| 482 |
$rs_cal_table_array[$i]=fread ($fp0,$this->rs_ecc_codewords); |
| 483 |
fclose ($fp0); |
| 484 |
|
| 485 |
$max_data_codewords = count($this->data_word); |
| 486 |
|
| 487 |
// preparation |
| 488 |
$j=0; |
| 489 |
$rs_block_number=0; |
| 490 |
$rs_temp[0]=""; |
| 491 |
for($i=0; $i<$max_data_codewords; $i++) |
| 492 |
{ |
| 493 |
$rs_temp[$rs_block_number].=chr($this->data_word[$i]); |
| 494 |
$j++; |
| 495 |
if ($j>=$this->rs_block_order[$rs_block_number+1]-$this->rs_ecc_codewords) |
| 496 |
{ |
| 497 |
$j=0; |
| 498 |
$rs_block_number++; |
| 499 |
$rs_temp[$rs_block_number]=""; |
| 500 |
} |
| 501 |
} |
| 502 |
|
| 503 |
// make |
| 504 |
$rs_block_order_num=count($this->rs_block_order); |
| 505 |
|
| 506 |
for($rs_block_number=0; $rs_block_number<$rs_block_order_num; $rs_block_number++) |
| 507 |
{ |
| 508 |
$rs_codewords=$this->rs_block_order[$rs_block_number+1]; |
| 509 |
$rs_data_codewords=$rs_codewords-$this->rs_ecc_codewords; |
| 510 |
|
| 511 |
$rstemp=$rs_temp[$rs_block_number].str_repeat(chr(0),$this->rs_ecc_codewords); |
| 512 |
$padding_data=str_repeat(chr(0),$rs_data_codewords); |
| 513 |
|
| 514 |
$j=$rs_data_codewords; |
| 515 |
while($j>0) |
| 516 |
{ |
| 517 |
$first=ord(substr($rstemp,0,1)); |
| 518 |
|
| 519 |
if ($first) |
| 520 |
{ |
| 521 |
$left_chr=substr($rstemp,1); |
| 522 |
$cal=$rs_cal_table_array[$first].$padding_data; |
| 523 |
$rstemp=$left_chr ^ $cal; |
| 524 |
} |
| 525 |
else |
| 526 |
$rstemp=substr($rstemp,1); |
| 527 |
$j--; |
| 528 |
} |
| 529 |
|
| 530 |
$this->data_word=array_merge($this->data_word,unpack("C*",$rstemp)); |
| 531 |
} |
| 532 |
} |
| 533 |
|
| 534 |
private function makeMatrix() |
| 535 |
{ |
| 536 |
// preparation |
| 537 |
$this->matrix = array_fill(0, $this->size, array_fill(0, $this->size, 0)); |
| 538 |
|
| 539 |
// mettre les words |
| 540 |
for($i=0; $i<$this->max_word; $i++) |
| 541 |
{ |
| 542 |
$word = $this->data_word[$i]; |
| 543 |
for($j=8; $j>0; $j--) |
| 544 |
{ |
| 545 |
$bit_pos = ($i<<3) + $j; |
| 546 |
$this->matrix[ $this->matrix_x_array[$bit_pos] ][ $this->matrix_y_array[$bit_pos] ] = ((255*($word & 1)) ^ $this->mask_array[$bit_pos] ); |
| 547 |
$word = $word >> 1; |
| 548 |
} |
| 549 |
} |
| 550 |
|
| 551 |
for($k=$this->matrix_remain; $k>0; $k--) |
| 552 |
{ |
| 553 |
$bit_pos = $k + ( $this->max_word <<3); |
| 554 |
$this->matrix[ $this->matrix_x_array[$bit_pos] ][ $this->matrix_y_array[$bit_pos] ] = ( 255 ^ $this->mask_array[$bit_pos] ); |
| 555 |
} |
| 556 |
|
| 557 |
// mask select |
| 558 |
$min_demerit_score=0; |
| 559 |
$hor_master=""; |
| 560 |
$ver_master=""; |
| 561 |
$k=0; |
| 562 |
while($k<$this->size) |
| 563 |
{ |
| 564 |
$l=0; |
| 565 |
while($l<$this->size) |
| 566 |
{ |
| 567 |
$hor_master=$hor_master.chr($this->matrix[$l][$k]); |
| 568 |
$ver_master=$ver_master.chr($this->matrix[$k][$l]); |
| 569 |
$l++; |
| 570 |
} |
| 571 |
$k++; |
| 572 |
} |
| 573 |
|
| 574 |
$i=0; |
| 575 |
$all_matrix=$this->size * $this->size; |
| 576 |
|
| 577 |
while ($i<8) |
| 578 |
{ |
| 579 |
$demerit_n1=0; |
| 580 |
$ptn_temp=array(); |
| 581 |
$bit= 1<< $i; |
| 582 |
$bit_r=(~$bit)&255; |
| 583 |
$bit_mask=str_repeat(chr($bit),$all_matrix); |
| 584 |
$hor = $hor_master & $bit_mask; |
| 585 |
$ver = $ver_master & $bit_mask; |
| 586 |
|
| 587 |
$ver_shift1=$ver.str_repeat(chr(170),$this->size); |
| 588 |
$ver_shift2=str_repeat(chr(170),$this->size).$ver; |
| 589 |
$ver_shift1_0=$ver.str_repeat(chr(0),$this->size); |
| 590 |
$ver_shift2_0=str_repeat(chr(0),$this->size).$ver; |
| 591 |
$ver_or=chunk_split(~($ver_shift1 | $ver_shift2),$this->size,chr(170)); |
| 592 |
$ver_and=chunk_split(~($ver_shift1_0 & $ver_shift2_0),$this->size,chr(170)); |
| 593 |
|
| 594 |
$hor=chunk_split(~$hor,$this->size,chr(170)); |
| 595 |
$ver=chunk_split(~$ver,$this->size,chr(170)); |
| 596 |
$hor=$hor.chr(170).$ver; |
| 597 |
|
| 598 |
$n1_search="/".str_repeat(chr(255),5)."+|".str_repeat(chr($bit_r),5)."+/"; |
| 599 |
$n3_search=chr($bit_r).chr(255).chr($bit_r).chr($bit_r).chr($bit_r).chr(255).chr($bit_r); |
| 600 |
|
| 601 |
$demerit_n3=substr_count($hor,$n3_search)*40; |
| 602 |
$demerit_n4=floor(abs(( (100* (substr_count($ver,chr($bit_r))/($this->byte_num)) )-50)/5))*10; |
| 603 |
|
| 604 |
$n2_search1="/".chr($bit_r).chr($bit_r)."+/"; |
| 605 |
$n2_search2="/".chr(255).chr(255)."+/"; |
| 606 |
$demerit_n2=0; |
| 607 |
preg_match_all($n2_search1,$ver_and,$ptn_temp); |
| 608 |
foreach($ptn_temp[0] as $str_temp) |
| 609 |
{ |
| 610 |
$demerit_n2+=(strlen($str_temp)-1); |
| 611 |
} |
| 612 |
$ptn_temp=array(); |
| 613 |
preg_match_all($n2_search2,$ver_or,$ptn_temp); |
| 614 |
foreach($ptn_temp[0] as $str_temp) |
| 615 |
{ |
| 616 |
$demerit_n2+=(strlen($str_temp)-1); |
| 617 |
} |
| 618 |
$demerit_n2*=3; |
| 619 |
|
| 620 |
$ptn_temp=array(); |
| 621 |
|
| 622 |
preg_match_all($n1_search,$hor,$ptn_temp); |
| 623 |
foreach($ptn_temp[0] as $str_temp) |
| 624 |
{ |
| 625 |
$demerit_n1+=(strlen($str_temp)-2); |
| 626 |
} |
| 627 |
$demerit_score=$demerit_n1+$demerit_n2+$demerit_n3+$demerit_n4; |
| 628 |
|
| 629 |
if ($demerit_score<=$min_demerit_score || $i==0) |
| 630 |
{ |
| 631 |
$mask_number=$i; |
| 632 |
$min_demerit_score=$demerit_score; |
| 633 |
} |
| 634 |
|
| 635 |
$i++; |
| 636 |
} |
| 637 |
|
| 638 |
$mask_content=1 << $mask_number; |
| 639 |
|
| 640 |
$format_information_value=(($this->ec << 3) | $mask_number); |
| 641 |
$format_information_array=array("101010000010010","101000100100101", |
| 642 |
"101111001111100","101101101001011","100010111111001","100000011001110", |
| 643 |
"100111110010111","100101010100000","111011111000100","111001011110011", |
| 644 |
"111110110101010","111100010011101","110011000101111","110001100011000", |
| 645 |
"110110001000001","110100101110110","001011010001001","001001110111110", |
| 646 |
"001110011100111","001100111010000","000011101100010","000001001010101", |
| 647 |
"000110100001100","000100000111011","011010101011111","011000001101000", |
| 648 |
"011111100110001","011101000000110","010010010110100","010000110000011", |
| 649 |
"010111011011010","010101111101101"); |
| 650 |
|
| 651 |
for($i=0; $i<15; $i++) |
| 652 |
{ |
| 653 |
$content=substr($format_information_array[$format_information_value],$i,1); |
| 654 |
|
| 655 |
$this->matrix[$this->format_information_x1[$i]][$this->format_information_y1[$i]]=$content * 255; |
| 656 |
$this->matrix[$this->format_information_x2[$i+1]][$this->format_information_y2[$i+1]]=$content * 255; |
| 657 |
} |
| 658 |
|
| 659 |
$this->final = unpack("C*", file_get_contents(dirname(__FILE__).'/data/modele'.$this->version.'.dat')); |
| 660 |
$this->qr_size = $this->size+8; |
| 661 |
|
| 662 |
for($x=0; $x<$this->size; $x++) |
| 663 |
{ |
| 664 |
for($y=0; $y<$this->size; $y++) |
| 665 |
{ |
| 666 |
if ($this->matrix[$x][$y] & $mask_content) |
| 667 |
$this->final[($x+4) + ($y+4)*$this->qr_size+1] = true; |
| 668 |
} |
| 669 |
} |
| 670 |
} |
| 671 |
} |
| 672 |
} |
| 673 |
|