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