1<?php
2
3// namespace changed for DokuWiki plugin
4namespace dokuwiki\plugin\twofactorgoogleauth;
5
6/**
7 *
8 * Copyright (c) 2016-2018 Kreative Software.
9 * Stripped down version inspired by Donald Becker, 2019
10 * Minimal SVG builder, composer support by Andreas Gohr, 2022
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 * @author Kreative Software
29 * @link https://github.com/kreativekorp/barcode
30 * @author Donald Becker
31 * @link https://github.com/psyon/php-qrcode
32 * @license MIT
33 */
34class QRCode
35{
36    protected $data;
37    protected $options;
38
39    /**
40     * @param string $data
41     * @param array $options
42     */
43    public function __construct($data, $options = [])
44    {
45        $defaults = [
46            's' => 'qrl'
47        ];
48        if (!is_array($options)) $options = [];
49
50        $this->data = $data;
51        $this->options = array_merge($defaults, $options);
52    }
53
54    /**
55     * Convenience method to quickly generate an SVG
56     *
57     * @param string $data
58     * @param array $options
59     * @return string
60     */
61    static public function svg($data, $options = [])
62    {
63        return (new QRCode($data, $options))->createSVG();
64    }
65
66    /**
67     * Create a SVG ready to be inlined
68     *
69     * @return string
70     */
71    public function createSVG()
72    {
73        $code = $this->dispatch_encode($this->data, $this->options);
74        $svg = sprintf('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 %d %d">', $code['s'][0], $code['s'][1]);
75        foreach ($code['b'] as $y => $row) {
76            foreach ($row as $x => $val) {
77                if ($val) {
78                    $svg .= sprintf('<rect x="%d" y="%d" width="1" height="1" />', $x, $y);
79                }
80            }
81        }
82        $svg .= '</svg>';
83
84        return $svg;
85    }
86
87    /* - - - - DISPATCH - - - - */
88
89    protected function dispatch_encode($data, $options)
90    {
91        switch (strtolower(preg_replace('/[^A-Za-z0-9]/', '', $options['s']))) {
92            case 'qrl':
93                return $this->qr_encode($data, 0);
94            case 'qrm':
95                return $this->qr_encode($data, 1);
96            case 'qrq':
97                return $this->qr_encode($data, 2);
98            case 'qrh':
99                return $this->qr_encode($data, 3);
100            default:
101                return $this->qr_encode($data, 0);
102        }
103    }
104
105
106    // region QR Encoder
107
108    protected function qr_encode($data, $ecl)
109    {
110        list($mode, $vers, $ec, $data) = $this->qr_encode_data($data, $ecl);
111        $data = $this->qr_encode_ec($data, $ec, $vers);
112        list($size, $mtx) = $this->qr_create_matrix($vers, $data);
113        list($mask, $mtx) = $this->qr_apply_best_mask($mtx, $size);
114        $mtx = $this->qr_finalize_matrix($mtx, $size, $ecl, $mask, $vers);
115        return array(
116            'g' => 'm',
117            'q' => array(4, 4, 4, 4),
118            's' => array($size, $size),
119            'b' => $mtx
120        );
121    }
122
123    protected function qr_encode_data($data, $ecl)
124    {
125        $mode = $this->qr_detect_mode($data);
126        $version = $this->qr_detect_version($data, $mode, $ecl);
127        $version_group = (($version < 10) ? 0 : (($version < 27) ? 1 : 2));
128        $ec_params = $this->qr_ec_params[($version - 1) * 4 + $ecl];
129        /* Don't cut off mid-character if exceeding capacity. */
130        $max_chars = $this->qr_capacity[$version - 1][$ecl][$mode];
131        if ($mode == 3) $max_chars <<= 1;
132        $data = substr($data, 0, $max_chars);
133        /* Convert from character level to bit level. */
134        switch ($mode) {
135            case 0:
136                $code = $this->qr_encode_numeric($data, $version_group);
137                break;
138            case 1:
139                $code = $this->qr_encode_alphanumeric($data, $version_group);
140                break;
141            case 2:
142                $code = $this->qr_encode_binary($data, $version_group);
143                break;
144            case 3:
145                $code = $this->qr_encode_kanji($data, $version_group);
146                break;
147        }
148        for ($i = 0; $i < 4; $i++) $code[] = 0;
149        while (count($code) % 8) $code[] = 0;
150        /* Convert from bit level to byte level. */
151        $data = array();
152        for ($i = 0, $n = count($code); $i < $n; $i += 8) {
153            $byte = 0;
154            if ($code[$i + 0]) $byte |= 0x80;
155            if ($code[$i + 1]) $byte |= 0x40;
156            if ($code[$i + 2]) $byte |= 0x20;
157            if ($code[$i + 3]) $byte |= 0x10;
158            if ($code[$i + 4]) $byte |= 0x08;
159            if ($code[$i + 5]) $byte |= 0x04;
160            if ($code[$i + 6]) $byte |= 0x02;
161            if ($code[$i + 7]) $byte |= 0x01;
162            $data[] = $byte;
163        }
164        for (
165            $i = count($data), $a = 1, $n = $ec_params[0];
166            $i < $n; $i++, $a ^= 1
167        ) {
168            $data[] = $a ? 236 : 17;
169        }
170        /* Return. */
171        return array($mode, $version, $ec_params, $data);
172    }
173
174    protected function qr_detect_mode($data)
175    {
176        $numeric = '/^[0-9]*$/';
177        $alphanumeric = '/^[0-9A-Z .\/:$%*+-]*$/';
178        $kanji = '/^([\x81-\x9F\xE0-\xEA][\x40-\xFC]|[\xEB][\x40-\xBF])*$/';
179        if (preg_match($numeric, $data)) return 0;
180        if (preg_match($alphanumeric, $data)) return 1;
181        if (preg_match($kanji, $data)) return 3;
182        return 2;
183    }
184
185    protected function qr_detect_version($data, $mode, $ecl)
186    {
187        $length = strlen($data);
188        if ($mode == 3) $length >>= 1;
189        for ($v = 0; $v < 40; $v++) {
190            if ($length <= $this->qr_capacity[$v][$ecl][$mode]) {
191                return $v + 1;
192            }
193        }
194        return 40;
195    }
196
197    protected function qr_encode_numeric($data, $version_group)
198    {
199        $code = array(0, 0, 0, 1);
200        $length = strlen($data);
201        switch ($version_group) {
202            case 2:  /* 27 - 40 */
203                $code[] = $length & 0x2000;
204                $code[] = $length & 0x1000;
205            case 1:  /* 10 - 26 */
206                $code[] = $length & 0x0800;
207                $code[] = $length & 0x0400;
208            case 0:  /* 1 - 9 */
209                $code[] = $length & 0x0200;
210                $code[] = $length & 0x0100;
211                $code[] = $length & 0x0080;
212                $code[] = $length & 0x0040;
213                $code[] = $length & 0x0020;
214                $code[] = $length & 0x0010;
215                $code[] = $length & 0x0008;
216                $code[] = $length & 0x0004;
217                $code[] = $length & 0x0002;
218                $code[] = $length & 0x0001;
219        }
220        for ($i = 0; $i < $length; $i += 3) {
221            $group = substr($data, $i, 3);
222            switch (strlen($group)) {
223                case 3:
224                    $code[] = $group & 0x200;
225                    $code[] = $group & 0x100;
226                    $code[] = $group & 0x080;
227                case 2:
228                    $code[] = $group & 0x040;
229                    $code[] = $group & 0x020;
230                    $code[] = $group & 0x010;
231                case 1:
232                    $code[] = $group & 0x008;
233                    $code[] = $group & 0x004;
234                    $code[] = $group & 0x002;
235                    $code[] = $group & 0x001;
236            }
237        }
238        return $code;
239    }
240
241    protected function qr_encode_alphanumeric($data, $version_group)
242    {
243        $alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
244        $code = array(0, 0, 1, 0);
245        $length = strlen($data);
246        switch ($version_group) {
247            case 2:  /* 27 - 40 */
248                $code[] = $length & 0x1000;
249                $code[] = $length & 0x0800;
250            case 1:  /* 10 - 26 */
251                $code[] = $length & 0x0400;
252                $code[] = $length & 0x0200;
253            case 0:  /* 1 - 9 */
254                $code[] = $length & 0x0100;
255                $code[] = $length & 0x0080;
256                $code[] = $length & 0x0040;
257                $code[] = $length & 0x0020;
258                $code[] = $length & 0x0010;
259                $code[] = $length & 0x0008;
260                $code[] = $length & 0x0004;
261                $code[] = $length & 0x0002;
262                $code[] = $length & 0x0001;
263        }
264        for ($i = 0; $i < $length; $i += 2) {
265            $group = substr($data, $i, 2);
266            if (strlen($group) > 1) {
267                $c1 = strpos($alphabet, substr($group, 0, 1));
268                $c2 = strpos($alphabet, substr($group, 1, 1));
269                $ch = $c1 * 45 + $c2;
270                $code[] = $ch & 0x400;
271                $code[] = $ch & 0x200;
272                $code[] = $ch & 0x100;
273                $code[] = $ch & 0x080;
274                $code[] = $ch & 0x040;
275                $code[] = $ch & 0x020;
276                $code[] = $ch & 0x010;
277                $code[] = $ch & 0x008;
278                $code[] = $ch & 0x004;
279                $code[] = $ch & 0x002;
280                $code[] = $ch & 0x001;
281            } else {
282                $ch = strpos($alphabet, $group);
283                $code[] = $ch & 0x020;
284                $code[] = $ch & 0x010;
285                $code[] = $ch & 0x008;
286                $code[] = $ch & 0x004;
287                $code[] = $ch & 0x002;
288                $code[] = $ch & 0x001;
289            }
290        }
291        return $code;
292    }
293
294    protected function qr_encode_binary($data, $version_group)
295    {
296        $code = array(0, 1, 0, 0);
297        $length = strlen($data);
298        switch ($version_group) {
299            case 2:  /* 27 - 40 */
300            case 1:  /* 10 - 26 */
301                $code[] = $length & 0x8000;
302                $code[] = $length & 0x4000;
303                $code[] = $length & 0x2000;
304                $code[] = $length & 0x1000;
305                $code[] = $length & 0x0800;
306                $code[] = $length & 0x0400;
307                $code[] = $length & 0x0200;
308                $code[] = $length & 0x0100;
309            case 0:  /* 1 - 9 */
310                $code[] = $length & 0x0080;
311                $code[] = $length & 0x0040;
312                $code[] = $length & 0x0020;
313                $code[] = $length & 0x0010;
314                $code[] = $length & 0x0008;
315                $code[] = $length & 0x0004;
316                $code[] = $length & 0x0002;
317                $code[] = $length & 0x0001;
318        }
319        for ($i = 0; $i < $length; $i++) {
320            $ch = ord(substr($data, $i, 1));
321            $code[] = $ch & 0x80;
322            $code[] = $ch & 0x40;
323            $code[] = $ch & 0x20;
324            $code[] = $ch & 0x10;
325            $code[] = $ch & 0x08;
326            $code[] = $ch & 0x04;
327            $code[] = $ch & 0x02;
328            $code[] = $ch & 0x01;
329        }
330        return $code;
331    }
332
333    protected function qr_encode_kanji($data, $version_group)
334    {
335        $code = array(1, 0, 0, 0);
336        $length = strlen($data);
337        switch ($version_group) {
338            case 2:  /* 27 - 40 */
339                $code[] = $length & 0x1000;
340                $code[] = $length & 0x0800;
341            case 1:  /* 10 - 26 */
342                $code[] = $length & 0x0400;
343                $code[] = $length & 0x0200;
344            case 0:  /* 1 - 9 */
345                $code[] = $length & 0x0100;
346                $code[] = $length & 0x0080;
347                $code[] = $length & 0x0040;
348                $code[] = $length & 0x0020;
349                $code[] = $length & 0x0010;
350                $code[] = $length & 0x0008;
351                $code[] = $length & 0x0004;
352                $code[] = $length & 0x0002;
353        }
354        for ($i = 0; $i < $length; $i += 2) {
355            $group = substr($data, $i, 2);
356            $c1 = ord(substr($group, 0, 1));
357            $c2 = ord(substr($group, 1, 1));
358            if ($c1 >= 0x81 && $c1 <= 0x9F && $c2 >= 0x40 && $c2 <= 0xFC) {
359                $ch = ($c1 - 0x81) * 0xC0 + ($c2 - 0x40);
360            } else if (
361                ($c1 >= 0xE0 && $c1 <= 0xEA && $c2 >= 0x40 && $c2 <= 0xFC) ||
362                ($c1 == 0xEB && $c2 >= 0x40 && $c2 <= 0xBF)
363            ) {
364                $ch = ($c1 - 0xC1) * 0xC0 + ($c2 - 0x40);
365            } else {
366                $ch = 0;
367            }
368            $code[] = $ch & 0x1000;
369            $code[] = $ch & 0x0800;
370            $code[] = $ch & 0x0400;
371            $code[] = $ch & 0x0200;
372            $code[] = $ch & 0x0100;
373            $code[] = $ch & 0x0080;
374            $code[] = $ch & 0x0040;
375            $code[] = $ch & 0x0020;
376            $code[] = $ch & 0x0010;
377            $code[] = $ch & 0x0008;
378            $code[] = $ch & 0x0004;
379            $code[] = $ch & 0x0002;
380            $code[] = $ch & 0x0001;
381        }
382        return $code;
383    }
384
385    protected function qr_encode_ec($data, $ec_params, $version)
386    {
387        $blocks = $this->qr_ec_split($data, $ec_params);
388        $ec_blocks = array();
389        for ($i = 0, $n = count($blocks); $i < $n; $i++) {
390            $ec_blocks[] = $this->qr_ec_divide($blocks[$i], $ec_params);
391        }
392        $data = $this->qr_ec_interleave($blocks);
393        $ec_data = $this->qr_ec_interleave($ec_blocks);
394        $code = array();
395        foreach ($data as $ch) {
396            $code[] = $ch & 0x80;
397            $code[] = $ch & 0x40;
398            $code[] = $ch & 0x20;
399            $code[] = $ch & 0x10;
400            $code[] = $ch & 0x08;
401            $code[] = $ch & 0x04;
402            $code[] = $ch & 0x02;
403            $code[] = $ch & 0x01;
404        }
405        foreach ($ec_data as $ch) {
406            $code[] = $ch & 0x80;
407            $code[] = $ch & 0x40;
408            $code[] = $ch & 0x20;
409            $code[] = $ch & 0x10;
410            $code[] = $ch & 0x08;
411            $code[] = $ch & 0x04;
412            $code[] = $ch & 0x02;
413            $code[] = $ch & 0x01;
414        }
415        for ($n = $this->qr_remainder_bits[$version - 1]; $n > 0; $n--) {
416            $code[] = 0;
417        }
418        return $code;
419    }
420
421    protected function qr_ec_split($data, $ec_params)
422    {
423        $blocks = array();
424        $offset = 0;
425        for ($i = $ec_params[2], $length = $ec_params[3]; $i > 0; $i--) {
426            $blocks[] = array_slice($data, $offset, $length);
427            $offset += $length;
428        }
429        for ($i = $ec_params[4], $length = $ec_params[5]; $i > 0; $i--) {
430            $blocks[] = array_slice($data, $offset, $length);
431            $offset += $length;
432        }
433        return $blocks;
434    }
435
436    protected function qr_ec_divide($data, $ec_params)
437    {
438        $num_data = count($data);
439        $num_error = $ec_params[1];
440        $generator = $this->qr_ec_polynomials[$num_error];
441        $message = $data;
442        for ($i = 0; $i < $num_error; $i++) {
443            $message[] = 0;
444        }
445        for ($i = 0; $i < $num_data; $i++) {
446            if ($message[$i]) {
447                $leadterm = $this->qr_log[$message[$i]];
448                for ($j = 0; $j <= $num_error; $j++) {
449                    $term = ($generator[$j] + $leadterm) % 255;
450                    $message[$i + $j] ^= $this->qr_exp[$term];
451                }
452            }
453        }
454        return array_slice($message, $num_data, $num_error);
455    }
456
457    protected function qr_ec_interleave($blocks)
458    {
459        $data = array();
460        $num_blocks = count($blocks);
461        for ($offset = 0; true; $offset++) {
462            $break = true;
463            for ($i = 0; $i < $num_blocks; $i++) {
464                if (isset($blocks[$i][$offset])) {
465                    $data[] = $blocks[$i][$offset];
466                    $break = false;
467                }
468            }
469            if ($break) break;
470        }
471        return $data;
472    }
473
474    protected function qr_create_matrix($version, $data)
475    {
476        $size = $version * 4 + 17;
477        $matrix = array();
478        for ($i = 0; $i < $size; $i++) {
479            $row = array();
480            for ($j = 0; $j < $size; $j++) {
481                $row[] = 0;
482            }
483            $matrix[] = $row;
484        }
485        /* Finder patterns. */
486        for ($i = 0; $i < 8; $i++) {
487            for ($j = 0; $j < 8; $j++) {
488                $m = (($i == 7 || $j == 7) ? 2 :
489                    (($i == 0 || $j == 0 || $i == 6 || $j == 6) ? 3 :
490                        (($i == 1 || $j == 1 || $i == 5 || $j == 5) ? 2 : 3)));
491                $matrix[$i][$j] = $m;
492                $matrix[$size - $i - 1][$j] = $m;
493                $matrix[$i][$size - $j - 1] = $m;
494            }
495        }
496        /* Alignment patterns. */
497        if ($version >= 2) {
498            $alignment = $this->qr_alignment_patterns[$version - 2];
499            foreach ($alignment as $i) {
500                foreach ($alignment as $j) {
501                    if (!$matrix[$i][$j]) {
502                        for ($ii = -2; $ii <= 2; $ii++) {
503                            for ($jj = -2; $jj <= 2; $jj++) {
504                                $m = (max(abs($ii), abs($jj)) & 1) ^ 3;
505                                $matrix[$i + $ii][$j + $jj] = $m;
506                            }
507                        }
508                    }
509                }
510            }
511        }
512        /* Timing patterns. */
513        for ($i = $size - 9; $i >= 8; $i--) {
514            $matrix[$i][6] = ($i & 1) ^ 3;
515            $matrix[6][$i] = ($i & 1) ^ 3;
516        }
517        /* Dark module. Such an ominous name for such an innocuous thing. */
518        $matrix[$size - 8][8] = 3;
519        /* Format information area. */
520        for ($i = 0; $i <= 8; $i++) {
521            if (!$matrix[$i][8]) $matrix[$i][8] = 1;
522            if (!$matrix[8][$i]) $matrix[8][$i] = 1;
523            if ($i && !$matrix[$size - $i][8]) $matrix[$size - $i][8] = 1;
524            if ($i && !$matrix[8][$size - $i]) $matrix[8][$size - $i] = 1;
525        }
526        /* Version information area. */
527        if ($version >= 7) {
528            for ($i = 9; $i < 12; $i++) {
529                for ($j = 0; $j < 6; $j++) {
530                    $matrix[$size - $i][$j] = 1;
531                    $matrix[$j][$size - $i] = 1;
532                }
533            }
534        }
535        /* Data. */
536        $col = $size - 1;
537        $row = $size - 1;
538        $dir = -1;
539        $offset = 0;
540        $length = count($data);
541        while ($col > 0 && $offset < $length) {
542            if (!$matrix[$row][$col]) {
543                $matrix[$row][$col] = $data[$offset] ? 5 : 4;
544                $offset++;
545            }
546            if (!$matrix[$row][$col - 1]) {
547                $matrix[$row][$col - 1] = $data[$offset] ? 5 : 4;
548                $offset++;
549            }
550            $row += $dir;
551            if ($row < 0 || $row >= $size) {
552                $dir = -$dir;
553                $row += $dir;
554                $col -= 2;
555                if ($col == 6) $col--;
556            }
557        }
558        return array($size, $matrix);
559    }
560
561    protected function qr_apply_best_mask($matrix, $size)
562    {
563        $best_mask = 0;
564        $best_matrix = $this->qr_apply_mask($matrix, $size, $best_mask);
565        $best_penalty = $this->qr_penalty($best_matrix, $size);
566        for ($test_mask = 1; $test_mask < 8; $test_mask++) {
567            $test_matrix = $this->qr_apply_mask($matrix, $size, $test_mask);
568            $test_penalty = $this->qr_penalty($test_matrix, $size);
569            if ($test_penalty < $best_penalty) {
570                $best_mask = $test_mask;
571                $best_matrix = $test_matrix;
572                $best_penalty = $test_penalty;
573            }
574        }
575        return array($best_mask, $best_matrix);
576    }
577
578    protected function qr_apply_mask($matrix, $size, $mask)
579    {
580        for ($i = 0; $i < $size; $i++) {
581            for ($j = 0; $j < $size; $j++) {
582                if ($matrix[$i][$j] >= 4) {
583                    if ($this->qr_mask($mask, $i, $j)) {
584                        $matrix[$i][$j] ^= 1;
585                    }
586                }
587            }
588        }
589        return $matrix;
590    }
591
592    protected function qr_mask($mask, $r, $c)
593    {
594        switch ($mask) {
595            case 0:
596                return !(($r + $c) % 2);
597            case 1:
598                return !(($r) % 2);
599            case 2:
600                return !(($c) % 3);
601            case 3:
602                return !(($r + $c) % 3);
603            case 4:
604                return !((floor(($r) / 2) + floor(($c) / 3)) % 2);
605            case 5:
606                return !(((($r * $c) % 2) + (($r * $c) % 3)));
607            case 6:
608                return !(((($r * $c) % 2) + (($r * $c) % 3)) % 2);
609            case 7:
610                return !(((($r + $c) % 2) + (($r * $c) % 3)) % 2);
611        }
612    }
613
614    protected function qr_penalty(&$matrix, $size)
615    {
616        $score = $this->qr_penalty_1($matrix, $size);
617        $score += $this->qr_penalty_2($matrix, $size);
618        $score += $this->qr_penalty_3($matrix, $size);
619        $score += $this->qr_penalty_4($matrix, $size);
620        return $score;
621    }
622
623    protected function qr_penalty_1(&$matrix, $size)
624    {
625        $score = 0;
626        for ($i = 0; $i < $size; $i++) {
627            $rowvalue = 0;
628            $rowcount = 0;
629            $colvalue = 0;
630            $colcount = 0;
631            for ($j = 0; $j < $size; $j++) {
632                $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0;
633                $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0;
634                if ($rv == $rowvalue) {
635                    $rowcount++;
636                } else {
637                    if ($rowcount >= 5) $score += $rowcount - 2;
638                    $rowvalue = $rv;
639                    $rowcount = 1;
640                }
641                if ($cv == $colvalue) {
642                    $colcount++;
643                } else {
644                    if ($colcount >= 5) $score += $colcount - 2;
645                    $colvalue = $cv;
646                    $colcount = 1;
647                }
648            }
649            if ($rowcount >= 5) $score += $rowcount - 2;
650            if ($colcount >= 5) $score += $colcount - 2;
651        }
652        return $score;
653    }
654
655    protected function qr_penalty_2(&$matrix, $size)
656    {
657        $score = 0;
658        for ($i = 1; $i < $size; $i++) {
659            for ($j = 1; $j < $size; $j++) {
660                $v1 = $matrix[$i - 1][$j - 1];
661                $v2 = $matrix[$i - 1][$j];
662                $v3 = $matrix[$i][$j - 1];
663                $v4 = $matrix[$i][$j];
664                $v1 = ($v1 == 5 || $v1 == 3) ? 1 : 0;
665                $v2 = ($v2 == 5 || $v2 == 3) ? 1 : 0;
666                $v3 = ($v3 == 5 || $v3 == 3) ? 1 : 0;
667                $v4 = ($v4 == 5 || $v4 == 3) ? 1 : 0;
668                if ($v1 == $v2 && $v2 == $v3 && $v3 == $v4) $score += 3;
669            }
670        }
671        return $score;
672    }
673
674    protected function qr_penalty_3(&$matrix, $size)
675    {
676        $score = 0;
677        for ($i = 0; $i < $size; $i++) {
678            $rowvalue = 0;
679            $colvalue = 0;
680            for ($j = 0; $j < 11; $j++) {
681                $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0;
682                $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0;
683                $rowvalue = (($rowvalue << 1) & 0x7FF) | $rv;
684                $colvalue = (($colvalue << 1) & 0x7FF) | $cv;
685            }
686            if ($rowvalue == 0x5D0 || $rowvalue == 0x5D) $score += 40;
687            if ($colvalue == 0x5D0 || $colvalue == 0x5D) $score += 40;
688            for ($j = 11; $j < $size; $j++) {
689                $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0;
690                $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0;
691                $rowvalue = (($rowvalue << 1) & 0x7FF) | $rv;
692                $colvalue = (($colvalue << 1) & 0x7FF) | $cv;
693                if ($rowvalue == 0x5D0 || $rowvalue == 0x5D) $score += 40;
694                if ($colvalue == 0x5D0 || $colvalue == 0x5D) $score += 40;
695            }
696        }
697        return $score;
698    }
699
700    protected function qr_penalty_4(&$matrix, $size)
701    {
702        $dark = 0;
703        for ($i = 0; $i < $size; $i++) {
704            for ($j = 0; $j < $size; $j++) {
705                if ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) {
706                    $dark++;
707                }
708            }
709        }
710        $dark *= 20;
711        $dark /= $size * $size;
712        $a = abs(floor($dark) - 10);
713        $b = abs(ceil($dark) - 10);
714        return min($a, $b) * 10;
715    }
716
717    protected function qr_finalize_matrix(
718        $matrix, $size, $ecl, $mask, $version
719    )
720    {
721        /* Format Info */
722        $format = $this->qr_format_info[$ecl * 8 + $mask];
723        $matrix[8][0] = $format[0];
724        $matrix[8][1] = $format[1];
725        $matrix[8][2] = $format[2];
726        $matrix[8][3] = $format[3];
727        $matrix[8][4] = $format[4];
728        $matrix[8][5] = $format[5];
729        $matrix[8][7] = $format[6];
730        $matrix[8][8] = $format[7];
731        $matrix[7][8] = $format[8];
732        $matrix[5][8] = $format[9];
733        $matrix[4][8] = $format[10];
734        $matrix[3][8] = $format[11];
735        $matrix[2][8] = $format[12];
736        $matrix[1][8] = $format[13];
737        $matrix[0][8] = $format[14];
738        $matrix[$size - 1][8] = $format[0];
739        $matrix[$size - 2][8] = $format[1];
740        $matrix[$size - 3][8] = $format[2];
741        $matrix[$size - 4][8] = $format[3];
742        $matrix[$size - 5][8] = $format[4];
743        $matrix[$size - 6][8] = $format[5];
744        $matrix[$size - 7][8] = $format[6];
745        $matrix[8][$size - 8] = $format[7];
746        $matrix[8][$size - 7] = $format[8];
747        $matrix[8][$size - 6] = $format[9];
748        $matrix[8][$size - 5] = $format[10];
749        $matrix[8][$size - 4] = $format[11];
750        $matrix[8][$size - 3] = $format[12];
751        $matrix[8][$size - 2] = $format[13];
752        $matrix[8][$size - 1] = $format[14];
753        /* Version Info */
754        if ($version >= 7) {
755            $version = $this->qr_version_info[$version - 7];
756            for ($i = 0; $i < 18; $i++) {
757                $r = $size - 9 - ($i % 3);
758                $c = 5 - floor($i / 3);
759                $matrix[$r][$c] = $version[$i];
760                $matrix[$c][$r] = $version[$i];
761            }
762        }
763        /* Patterns & Data */
764        for ($i = 0; $i < $size; $i++) {
765            for ($j = 0; $j < $size; $j++) {
766                $matrix[$i][$j] &= 1;
767            }
768        }
769        return $matrix;
770    }
771
772    /*  maximum encodable characters = $qr_capacity [ (version - 1) ]  */
773    /*    [ (0 for L, 1 for M, 2 for Q, 3 for H)                    ]  */
774    /*    [ (0 for numeric, 1 for alpha, 2 for binary, 3 for kanji) ]  */
775    protected $qr_capacity = [
776        [[41, 25, 17, 10], [34, 20, 14, 8],
777            [27, 16, 11, 7], [17, 10, 7, 4]],
778        [[77, 47, 32, 20], [63, 38, 26, 16],
779            [48, 29, 20, 12], [34, 20, 14, 8]],
780        [[127, 77, 53, 32], [101, 61, 42, 26],
781            [77, 47, 32, 20], [58, 35, 24, 15]],
782        [[187, 114, 78, 48], [149, 90, 62, 38],
783            [111, 67, 46, 28], [82, 50, 34, 21]],
784        [[255, 154, 106, 65], [202, 122, 84, 52],
785            [144, 87, 60, 37], [106, 64, 44, 27]],
786        [[322, 195, 134, 82], [255, 154, 106, 65],
787            [178, 108, 74, 45], [139, 84, 58, 36]],
788        [[370, 224, 154, 95], [293, 178, 122, 75],
789            [207, 125, 86, 53], [154, 93, 64, 39]],
790        [[461, 279, 192, 118], [365, 221, 152, 93],
791            [259, 157, 108, 66], [202, 122, 84, 52]],
792        [[552, 335, 230, 141], [432, 262, 180, 111],
793            [312, 189, 130, 80], [235, 143, 98, 60]],
794        [[652, 395, 271, 167], [513, 311, 213, 131],
795            [364, 221, 151, 93], [288, 174, 119, 74]],
796        [[772, 468, 321, 198], [604, 366, 251, 155],
797            [427, 259, 177, 109], [331, 200, 137, 85]],
798        [[883, 535, 367, 226], [691, 419, 287, 177],
799            [489, 296, 203, 125], [374, 227, 155, 96]],
800        [[1022, 619, 425, 262], [796, 483, 331, 204],
801            [580, 352, 241, 149], [427, 259, 177, 109]],
802        [[1101, 667, 458, 282], [871, 528, 362, 223],
803            [621, 376, 258, 159], [468, 283, 194, 120]],
804        [[1250, 758, 520, 320], [991, 600, 412, 254],
805            [703, 426, 292, 180], [530, 321, 220, 136]],
806        [[1408, 854, 586, 361], [1082, 656, 450, 277],
807            [775, 470, 322, 198], [602, 365, 250, 154]],
808        [[1548, 938, 644, 397], [1212, 734, 504, 310],
809            [876, 531, 364, 224], [674, 408, 280, 173]],
810        [[1725, 1046, 718, 442], [1346, 816, 560, 345],
811            [948, 574, 394, 243], [746, 452, 310, 191]],
812        [[1903, 1153, 792, 488], [1500, 909, 624, 384],
813            [1063, 644, 442, 272], [813, 493, 338, 208]],
814        [[2061, 1249, 858, 528], [1600, 970, 666, 410],
815            [1159, 702, 482, 297], [919, 557, 382, 235]],
816        [[2232, 1352, 929, 572], [1708, 1035, 711, 438],
817            [1224, 742, 509, 314], [969, 587, 403, 248]],
818        [[2409, 1460, 1003, 618], [1872, 1134, 779, 480],
819            [1358, 823, 565, 348], [1056, 640, 439, 270]],
820        [[2620, 1588, 1091, 672], [2059, 1248, 857, 528],
821            [1468, 890, 611, 376], [1108, 672, 461, 284]],
822        [[2812, 1704, 1171, 721], [2188, 1326, 911, 561],
823            [1588, 963, 661, 407], [1228, 744, 511, 315]],
824        [[3057, 1853, 1273, 784], [2395, 1451, 997, 614],
825            [1718, 1041, 715, 440], [1286, 779, 535, 330]],
826        [[3283, 1990, 1367, 842], [2544, 1542, 1059, 652],
827            [1804, 1094, 751, 462], [1425, 864, 593, 365]],
828        [[3517, 2132, 1465, 902], [2701, 1637, 1125, 692],
829            [1933, 1172, 805, 496], [1501, 910, 625, 385]],
830        [[3669, 2223, 1528, 940], [2857, 1732, 1190, 732],
831            [2085, 1263, 868, 534], [1581, 958, 658, 405]],
832        [[3909, 2369, 1628, 1002], [3035, 1839, 1264, 778],
833            [2181, 1322, 908, 559], [1677, 1016, 698, 430]],
834        [[4158, 2520, 1732, 1066], [3289, 1994, 1370, 843],
835            [2358, 1429, 982, 604], [1782, 1080, 742, 457]],
836        [[4417, 2677, 1840, 1132], [3486, 2113, 1452, 894],
837            [2473, 1499, 1030, 634], [1897, 1150, 790, 486]],
838        [[4686, 2840, 1952, 1201], [3693, 2238, 1538, 947],
839            [2670, 1618, 1112, 684], [2022, 1226, 842, 518]],
840        [[4965, 3009, 2068, 1273], [3909, 2369, 1628, 1002],
841            [2805, 1700, 1168, 719], [2157, 1307, 898, 553]],
842        [[5253, 3183, 2188, 1347], [4134, 2506, 1722, 1060],
843            [2949, 1787, 1228, 756], [2301, 1394, 958, 590]],
844        [[5529, 3351, 2303, 1417], [4343, 2632, 1809, 1113],
845            [3081, 1867, 1283, 790], [2361, 1431, 983, 605]],
846        [[5836, 3537, 2431, 1496], [4588, 2780, 1911, 1176],
847            [3244, 1966, 1351, 832], [2524, 1530, 1051, 647]],
848        [[6153, 3729, 2563, 1577], [4775, 2894, 1989, 1224],
849            [3417, 2071, 1423, 876], [2625, 1591, 1093, 673]],
850        [[6479, 3927, 2699, 1661], [5039, 3054, 2099, 1292],
851            [3599, 2181, 1499, 923], [2735, 1658, 1139, 701]],
852        [[6743, 4087, 2809, 1729], [5313, 3220, 2213, 1362],
853            [3791, 2298, 1579, 972], [2927, 1774, 1219, 750]],
854        [[7089, 4296, 2953, 1817], [5596, 3391, 2331, 1435],
855            [3993, 2420, 1663, 1024], [3057, 1852, 1273, 784]],
856    ];
857
858    /*  $qr_ec_params[                                              */
859    /*    4 * (version - 1) + (0 for L, 1 for M, 2 for Q, 3 for H)  */
860    /*  ] = array(                                                  */
861    /*    total number of data codewords,                           */
862    /*    number of error correction codewords per block,           */
863    /*    number of blocks in first group,                          */
864    /*    number of data codewords per block in first group,        */
865    /*    number of blocks in second group,                         */
866    /*    number of data codewords per block in second group        */
867    /*  );                                                          */
868    protected $qr_ec_params = [
869        [19, 7, 1, 19, 0, 0],
870        [16, 10, 1, 16, 0, 0],
871        [13, 13, 1, 13, 0, 0],
872        [9, 17, 1, 9, 0, 0],
873        [34, 10, 1, 34, 0, 0],
874        [28, 16, 1, 28, 0, 0],
875        [22, 22, 1, 22, 0, 0],
876        [16, 28, 1, 16, 0, 0],
877        [55, 15, 1, 55, 0, 0],
878        [44, 26, 1, 44, 0, 0],
879        [34, 18, 2, 17, 0, 0],
880        [26, 22, 2, 13, 0, 0],
881        [80, 20, 1, 80, 0, 0],
882        [64, 18, 2, 32, 0, 0],
883        [48, 26, 2, 24, 0, 0],
884        [36, 16, 4, 9, 0, 0],
885        [108, 26, 1, 108, 0, 0],
886        [86, 24, 2, 43, 0, 0],
887        [62, 18, 2, 15, 2, 16],
888        [46, 22, 2, 11, 2, 12],
889        [136, 18, 2, 68, 0, 0],
890        [108, 16, 4, 27, 0, 0],
891        [76, 24, 4, 19, 0, 0],
892        [60, 28, 4, 15, 0, 0],
893        [156, 20, 2, 78, 0, 0],
894        [124, 18, 4, 31, 0, 0],
895        [88, 18, 2, 14, 4, 15],
896        [66, 26, 4, 13, 1, 14],
897        [194, 24, 2, 97, 0, 0],
898        [154, 22, 2, 38, 2, 39],
899        [110, 22, 4, 18, 2, 19],
900        [86, 26, 4, 14, 2, 15],
901        [232, 30, 2, 116, 0, 0],
902        [182, 22, 3, 36, 2, 37],
903        [132, 20, 4, 16, 4, 17],
904        [100, 24, 4, 12, 4, 13],
905        [274, 18, 2, 68, 2, 69],
906        [216, 26, 4, 43, 1, 44],
907        [154, 24, 6, 19, 2, 20],
908        [122, 28, 6, 15, 2, 16],
909        [324, 20, 4, 81, 0, 0],
910        [254, 30, 1, 50, 4, 51],
911        [180, 28, 4, 22, 4, 23],
912        [140, 24, 3, 12, 8, 13],
913        [370, 24, 2, 92, 2, 93],
914        [290, 22, 6, 36, 2, 37],
915        [206, 26, 4, 20, 6, 21],
916        [158, 28, 7, 14, 4, 15],
917        [428, 26, 4, 107, 0, 0],
918        [334, 22, 8, 37, 1, 38],
919        [244, 24, 8, 20, 4, 21],
920        [180, 22, 12, 11, 4, 12],
921        [461, 30, 3, 115, 1, 116],
922        [365, 24, 4, 40, 5, 41],
923        [261, 20, 11, 16, 5, 17],
924        [197, 24, 11, 12, 5, 13],
925        [523, 22, 5, 87, 1, 88],
926        [415, 24, 5, 41, 5, 42],
927        [295, 30, 5, 24, 7, 25],
928        [223, 24, 11, 12, 7, 13],
929        [589, 24, 5, 98, 1, 99],
930        [453, 28, 7, 45, 3, 46],
931        [325, 24, 15, 19, 2, 20],
932        [253, 30, 3, 15, 13, 16],
933        [647, 28, 1, 107, 5, 108],
934        [507, 28, 10, 46, 1, 47],
935        [367, 28, 1, 22, 15, 23],
936        [283, 28, 2, 14, 17, 15],
937        [721, 30, 5, 120, 1, 121],
938        [563, 26, 9, 43, 4, 44],
939        [397, 28, 17, 22, 1, 23],
940        [313, 28, 2, 14, 19, 15],
941        [795, 28, 3, 113, 4, 114],
942        [627, 26, 3, 44, 11, 45],
943        [445, 26, 17, 21, 4, 22],
944        [341, 26, 9, 13, 16, 14],
945        [861, 28, 3, 107, 5, 108],
946        [669, 26, 3, 41, 13, 42],
947        [485, 30, 15, 24, 5, 25],
948        [385, 28, 15, 15, 10, 16],
949        [932, 28, 4, 116, 4, 117],
950        [714, 26, 17, 42, 0, 0],
951        [512, 28, 17, 22, 6, 23],
952        [406, 30, 19, 16, 6, 17],
953        [1006, 28, 2, 111, 7, 112],
954        [782, 28, 17, 46, 0, 0],
955        [568, 30, 7, 24, 16, 25],
956        [442, 24, 34, 13, 0, 0],
957        [1094, 30, 4, 121, 5, 122],
958        [860, 28, 4, 47, 14, 48],
959        [614, 30, 11, 24, 14, 25],
960        [464, 30, 16, 15, 14, 16],
961        [1174, 30, 6, 117, 4, 118],
962        [914, 28, 6, 45, 14, 46],
963        [664, 30, 11, 24, 16, 25],
964        [514, 30, 30, 16, 2, 17],
965        [1276, 26, 8, 106, 4, 107],
966        [1000, 28, 8, 47, 13, 48],
967        [718, 30, 7, 24, 22, 25],
968        [538, 30, 22, 15, 13, 16],
969        [1370, 28, 10, 114, 2, 115],
970        [1062, 28, 19, 46, 4, 47],
971        [754, 28, 28, 22, 6, 23],
972        [596, 30, 33, 16, 4, 17],
973        [1468, 30, 8, 122, 4, 123],
974        [1128, 28, 22, 45, 3, 46],
975        [808, 30, 8, 23, 26, 24],
976        [628, 30, 12, 15, 28, 16],
977        [1531, 30, 3, 117, 10, 118],
978        [1193, 28, 3, 45, 23, 46],
979        [871, 30, 4, 24, 31, 25],
980        [661, 30, 11, 15, 31, 16],
981        [1631, 30, 7, 116, 7, 117],
982        [1267, 28, 21, 45, 7, 46],
983        [911, 30, 1, 23, 37, 24],
984        [701, 30, 19, 15, 26, 16],
985        [1735, 30, 5, 115, 10, 116],
986        [1373, 28, 19, 47, 10, 48],
987        [985, 30, 15, 24, 25, 25],
988        [745, 30, 23, 15, 25, 16],
989        [1843, 30, 13, 115, 3, 116],
990        [1455, 28, 2, 46, 29, 47],
991        [1033, 30, 42, 24, 1, 25],
992        [793, 30, 23, 15, 28, 16],
993        [1955, 30, 17, 115, 0, 0],
994        [1541, 28, 10, 46, 23, 47],
995        [1115, 30, 10, 24, 35, 25],
996        [845, 30, 19, 15, 35, 16],
997        [2071, 30, 17, 115, 1, 116],
998        [1631, 28, 14, 46, 21, 47],
999        [1171, 30, 29, 24, 19, 25],
1000        [901, 30, 11, 15, 46, 16],
1001        [2191, 30, 13, 115, 6, 116],
1002        [1725, 28, 14, 46, 23, 47],
1003        [1231, 30, 44, 24, 7, 25],
1004        [961, 30, 59, 16, 1, 17],
1005        [2306, 30, 12, 121, 7, 122],
1006        [1812, 28, 12, 47, 26, 48],
1007        [1286, 30, 39, 24, 14, 25],
1008        [986, 30, 22, 15, 41, 16],
1009        [2434, 30, 6, 121, 14, 122],
1010        [1914, 28, 6, 47, 34, 48],
1011        [1354, 30, 46, 24, 10, 25],
1012        [1054, 30, 2, 15, 64, 16],
1013        [2566, 30, 17, 122, 4, 123],
1014        [1992, 28, 29, 46, 14, 47],
1015        [1426, 30, 49, 24, 10, 25],
1016        [1096, 30, 24, 15, 46, 16],
1017        [2702, 30, 4, 122, 18, 123],
1018        [2102, 28, 13, 46, 32, 47],
1019        [1502, 30, 48, 24, 14, 25],
1020        [1142, 30, 42, 15, 32, 16],
1021        [2812, 30, 20, 117, 4, 118],
1022        [2216, 28, 40, 47, 7, 48],
1023        [1582, 30, 43, 24, 22, 25],
1024        [1222, 30, 10, 15, 67, 16],
1025        [2956, 30, 19, 118, 6, 119],
1026        [2334, 28, 18, 47, 31, 48],
1027        [1666, 30, 34, 24, 34, 25],
1028        [1276, 30, 20, 15, 61, 16],
1029    ];
1030
1031    protected $qr_ec_polynomials = [
1032        7 => [
1033            0, 87, 229, 146, 149, 238, 102, 21
1034        ],
1035        10 => [
1036            0, 251, 67, 46, 61, 118, 70, 64, 94, 32, 45
1037        ],
1038        13 => [
1039            0, 74, 152, 176, 100, 86, 100,
1040            106, 104, 130, 218, 206, 140, 78
1041        ],
1042        15 => [
1043            0, 8, 183, 61, 91, 202, 37, 51,
1044            58, 58, 237, 140, 124, 5, 99, 105
1045        ],
1046        16 => [
1047            0, 120, 104, 107, 109, 102, 161, 76, 3,
1048            91, 191, 147, 169, 182, 194, 225, 120
1049        ],
1050        17 => [
1051            0, 43, 139, 206, 78, 43, 239, 123, 206,
1052            214, 147, 24, 99, 150, 39, 243, 163, 136
1053        ],
1054        18 => [
1055            0, 215, 234, 158, 94, 184, 97, 118, 170, 79,
1056            187, 152, 148, 252, 179, 5, 98, 96, 153
1057        ],
1058        20 => [
1059            0, 17, 60, 79, 50, 61, 163, 26, 187, 202, 180,
1060            221, 225, 83, 239, 156, 164, 212, 212, 188, 190
1061        ],
1062        22 => [
1063            0, 210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200,
1064            74, 8, 172, 98, 80, 219, 134, 160, 105, 165, 231
1065        ],
1066        24 => [
1067            0, 229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169,
1068            152, 192, 226, 228, 218, 111, 0, 117, 232, 87, 96, 227, 21
1069        ],
1070        26 => [
1071            0, 173, 125, 158, 2, 103, 182, 118, 17,
1072            145, 201, 111, 28, 165, 53, 161, 21, 245,
1073            142, 13, 102, 48, 227, 153, 145, 218, 70
1074        ],
1075        28 => [
1076            0, 168, 223, 200, 104, 224, 234, 108, 180,
1077            110, 190, 195, 147, 205, 27, 232, 201, 21, 43,
1078            245, 87, 42, 195, 212, 119, 242, 37, 9, 123
1079        ],
1080        30 => [
1081            0, 41, 173, 145, 152, 216, 31, 179, 182, 50, 48,
1082            110, 86, 239, 96, 222, 125, 42, 173, 226, 193,
1083            224, 130, 156, 37, 251, 216, 238, 40, 192, 180
1084        ],
1085    ];
1086
1087    protected $qr_log = [
1088        0, 0, 1, 25, 2, 50, 26, 198,
1089        3, 223, 51, 238, 27, 104, 199, 75,
1090        4, 100, 224, 14, 52, 141, 239, 129,
1091        28, 193, 105, 248, 200, 8, 76, 113,
1092        5, 138, 101, 47, 225, 36, 15, 33,
1093        53, 147, 142, 218, 240, 18, 130, 69,
1094        29, 181, 194, 125, 106, 39, 249, 185,
1095        201, 154, 9, 120, 77, 228, 114, 166,
1096        6, 191, 139, 98, 102, 221, 48, 253,
1097        226, 152, 37, 179, 16, 145, 34, 136,
1098        54, 208, 148, 206, 143, 150, 219, 189,
1099        241, 210, 19, 92, 131, 56, 70, 64,
1100        30, 66, 182, 163, 195, 72, 126, 110,
1101        107, 58, 40, 84, 250, 133, 186, 61,
1102        202, 94, 155, 159, 10, 21, 121, 43,
1103        78, 212, 229, 172, 115, 243, 167, 87,
1104        7, 112, 192, 247, 140, 128, 99, 13,
1105        103, 74, 222, 237, 49, 197, 254, 24,
1106        227, 165, 153, 119, 38, 184, 180, 124,
1107        17, 68, 146, 217, 35, 32, 137, 46,
1108        55, 63, 209, 91, 149, 188, 207, 205,
1109        144, 135, 151, 178, 220, 252, 190, 97,
1110        242, 86, 211, 171, 20, 42, 93, 158,
1111        132, 60, 57, 83, 71, 109, 65, 162,
1112        31, 45, 67, 216, 183, 123, 164, 118,
1113        196, 23, 73, 236, 127, 12, 111, 246,
1114        108, 161, 59, 82, 41, 157, 85, 170,
1115        251, 96, 134, 177, 187, 204, 62, 90,
1116        203, 89, 95, 176, 156, 169, 160, 81,
1117        11, 245, 22, 235, 122, 117, 44, 215,
1118        79, 174, 213, 233, 230, 231, 173, 232,
1119        116, 214, 244, 234, 168, 80, 88, 175,
1120    ];
1121
1122    protected $qr_exp = [
1123        1, 2, 4, 8, 16, 32, 64, 128,
1124        29, 58, 116, 232, 205, 135, 19, 38,
1125        76, 152, 45, 90, 180, 117, 234, 201,
1126        143, 3, 6, 12, 24, 48, 96, 192,
1127        157, 39, 78, 156, 37, 74, 148, 53,
1128        106, 212, 181, 119, 238, 193, 159, 35,
1129        70, 140, 5, 10, 20, 40, 80, 160,
1130        93, 186, 105, 210, 185, 111, 222, 161,
1131        95, 190, 97, 194, 153, 47, 94, 188,
1132        101, 202, 137, 15, 30, 60, 120, 240,
1133        253, 231, 211, 187, 107, 214, 177, 127,
1134        254, 225, 223, 163, 91, 182, 113, 226,
1135        217, 175, 67, 134, 17, 34, 68, 136,
1136        13, 26, 52, 104, 208, 189, 103, 206,
1137        129, 31, 62, 124, 248, 237, 199, 147,
1138        59, 118, 236, 197, 151, 51, 102, 204,
1139        133, 23, 46, 92, 184, 109, 218, 169,
1140        79, 158, 33, 66, 132, 21, 42, 84,
1141        168, 77, 154, 41, 82, 164, 85, 170,
1142        73, 146, 57, 114, 228, 213, 183, 115,
1143        230, 209, 191, 99, 198, 145, 63, 126,
1144        252, 229, 215, 179, 123, 246, 241, 255,
1145        227, 219, 171, 75, 150, 49, 98, 196,
1146        149, 55, 110, 220, 165, 87, 174, 65,
1147        130, 25, 50, 100, 200, 141, 7, 14,
1148        28, 56, 112, 224, 221, 167, 83, 166,
1149        81, 162, 89, 178, 121, 242, 249, 239,
1150        195, 155, 43, 86, 172, 69, 138, 9,
1151        18, 36, 72, 144, 61, 122, 244, 245,
1152        247, 243, 251, 235, 203, 139, 11, 22,
1153        44, 88, 176, 125, 250, 233, 207, 131,
1154        27, 54, 108, 216, 173, 71, 142, 1,
1155    ];
1156
1157    protected $qr_remainder_bits = [
1158        0, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3,
1159        4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
1160    ];
1161
1162    protected $qr_alignment_patterns = [
1163        [6, 18],
1164        [6, 22],
1165        [6, 26],
1166        [6, 30],
1167        [6, 34],
1168        [6, 22, 38],
1169        [6, 24, 42],
1170        [6, 26, 46],
1171        [6, 28, 50],
1172        [6, 30, 54],
1173        [6, 32, 58],
1174        [6, 34, 62],
1175        [6, 26, 46, 66],
1176        [6, 26, 48, 70],
1177        [6, 26, 50, 74],
1178        [6, 30, 54, 78],
1179        [6, 30, 56, 82],
1180        [6, 30, 58, 86],
1181        [6, 34, 62, 90],
1182        [6, 28, 50, 72, 94],
1183        [6, 26, 50, 74, 98],
1184        [6, 30, 54, 78, 102],
1185        [6, 28, 54, 80, 106],
1186        [6, 32, 58, 84, 110],
1187        [6, 30, 58, 86, 114],
1188        [6, 34, 62, 90, 118],
1189        [6, 26, 50, 74, 98, 122],
1190        [6, 30, 54, 78, 102, 126],
1191        [6, 26, 52, 78, 104, 130],
1192        [6, 30, 56, 82, 108, 134],
1193        [6, 34, 60, 86, 112, 138],
1194        [6, 30, 58, 86, 114, 142],
1195        [6, 34, 62, 90, 118, 146],
1196        [6, 30, 54, 78, 102, 126, 150],
1197        [6, 24, 50, 76, 102, 128, 154],
1198        [6, 28, 54, 80, 106, 132, 158],
1199        [6, 32, 58, 84, 110, 136, 162],
1200        [6, 26, 54, 82, 110, 138, 166],
1201        [6, 30, 58, 86, 114, 142, 170],
1202    ];
1203
1204    /*  format info string = $qr_format_info[            */
1205    /*    (0 for L, 8 for M, 16 for Q, 24 for H) + mask  */
1206    /*  ];                                               */
1207    protected $qr_format_info = [
1208        [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0],
1209        [1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1],
1210        [1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0],
1211        [1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1],
1212        [1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1],
1213        [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0],
1214        [1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
1215        [1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0],
1216        [1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
1217        [1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1],
1218        [1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0],
1219        [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1],
1220        [1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1],
1221        [1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0],
1222        [1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1],
1223        [1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0],
1224        [0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1],
1225        [0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
1226        [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1],
1227        [0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0],
1228        [0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0],
1229        [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1],
1230        [0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0],
1231        [0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1],
1232        [0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1],
1233        [0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0],
1234        [0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1],
1235        [0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0],
1236        [0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0],
1237        [0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1],
1238        [0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
1239        [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1],
1240    ];
1241
1242    /*  version info string = $qr_version_info[ (version - 7) ]  */
1243    protected $qr_version_info = [
1244        [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0],
1245        [0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
1246        [0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1],
1247        [0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1],
1248        [0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0],
1249        [0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0],
1250        [0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1],
1251        [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1],
1252        [0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
1253        [0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
1254        [0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1],
1255        [0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1],
1256        [0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0],
1257        [0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0],
1258        [0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1],
1259        [0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1],
1260        [0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0],
1261        [0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0],
1262        [0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1],
1263        [0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1],
1264        [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0],
1265        [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0],
1266        [0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1],
1267        [0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1],
1268        [0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0],
1269        [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1],
1270        [1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0],
1271        [1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0],
1272        [1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1],
1273        [1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1],
1274        [1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0],
1275        [1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0],
1276        [1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
1277        [1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1],
1278    ];
1279}
1280