qrcode.class.php 20 KB

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