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