ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
qrcode.php
Go to the documentation of this file.
1<?php
2//============================================================+
3// File name : qrcode.php
4// Version : 1.0.010
5// Begin : 2010-03-22
6// Last Update : 2012-07-25
7// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9// -------------------------------------------------------------------
10// Copyright (C) 2010-2012 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can redistribute it and/or modify it
15// under the terms of the GNU Lesser General Public License as
16// published by the Free Software Foundation, either version 3 of the
17// License, or (at your option) any later version.
18//
19// TCPDF is distributed in the hope that it will be useful, but
20// WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22// See the GNU Lesser General Public License for more details.
23//
24// You should have received a copy of the GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// DESCRIPTION :
31//
32// Class to create QR-code arrays for TCPDF class.
33// QR Code symbol is a 2D barcode that can be scanned by
34// handy terminals such as a mobile phone with CCD.
35// The capacity of QR Code is up to 7000 digits or 4000
36// characters, and has high robustness.
37// This class supports QR Code model 2, described in
38// JIS (Japanese Industrial Standards) X0510:2004
39// or ISO/IEC 18004.
40// Currently the following features are not supported:
41// ECI and FNC1 mode, Micro QR Code, QR Code model 1,
42// Structured mode.
43//
44// This class is derived from the following projects:
45// ---------------------------------------------------------
46// "PHP QR Code encoder"
47// License: GNU-LGPLv3
48// Copyright (C) 2010 by Dominik Dzienia <deltalab at poczta dot fm>
49// http://phpqrcode.sourceforge.net/
50// https://sourceforge.net/projects/phpqrcode/
51//
52// The "PHP QR Code encoder" is based on
53// "C libqrencode library" (ver. 3.1.1)
54// License: GNU-LGPL 2.1
55// Copyright (C) 2006-2010 by Kentaro Fukuchi
56// http://megaui.net/fukuchi/works/qrencode/index.en.html
57//
58// Reed-Solomon code encoder is written by Phil Karn, KA9Q.
59// Copyright (C) 2002-2006 Phil Karn, KA9Q
60//
61// QR Code is registered trademark of DENSO WAVE INCORPORATED
62// http://www.denso-wave.com/qrcode/index-e.html
63// ---------------------------------------------------------
64//============================================================+
65
82// definitions
83if (!defined('QRCODEDEFS')) {
84
88 define('QRCODEDEFS', true);
89
90 // -----------------------------------------------------
91
92 // Encoding modes (characters which can be encoded in QRcode)
93
97 define('QR_MODE_NL', -1);
98
102 define('QR_MODE_NM', 0);
103
107 define('QR_MODE_AN', 1);
108
112 define('QR_MODE_8B', 2);
113
117 define('QR_MODE_KJ', 3);
118
122 define('QR_MODE_ST', 4);
123
124 // -----------------------------------------------------
125
126 // Levels of error correction.
127 // QRcode has a function of an error correcting for miss reading that white is black.
128 // Error correcting is defined in 4 level as below.
129
133 define('QR_ECLEVEL_L', 0);
134
138 define('QR_ECLEVEL_M', 1);
139
143 define('QR_ECLEVEL_Q', 2);
144
148 define('QR_ECLEVEL_H', 3);
149
150 // -----------------------------------------------------
151
152 // Version. Size of QRcode is defined as version.
153 // Version is from 1 to 40.
154 // Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
155 // So version 40 is 177*177 matrix.
156
160 define('QRSPEC_VERSION_MAX', 40);
161
165 define('QRSPEC_WIDTH_MAX', 177);
166
167 // -----------------------------------------------------
168
172 define('QRCAP_WIDTH', 0);
173
177 define('QRCAP_WORDS', 1);
178
182 define('QRCAP_REMINDER', 2);
183
187 define('QRCAP_EC', 3);
188
189 // -----------------------------------------------------
190
191 // Structure (currently usupported)
192
196 define('STRUCTURE_HEADER_BITS', 20);
197
201 define('MAX_STRUCTURED_SYMBOLS', 16);
202
203 // -----------------------------------------------------
204
205 // Masks
206
210 define('N1', 3);
211
215 define('N2', 3);
216
220 define('N3', 40);
221
225 define('N4', 10);
226
227 // -----------------------------------------------------
228
229 // Optimization settings
230
234 define('QR_FIND_BEST_MASK', true);
235
239 define('QR_FIND_FROM_RANDOM', 2);
240
244 define('QR_DEFAULT_MASK', 2);
245
246 // -----------------------------------------------------
247
248} // end of definitions
249
250// #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
251
252// for compatibility with PHP4
253if (!function_exists('str_split')) {
260 function str_split($string, $split_length=1) {
261 if ((strlen($string) > $split_length) OR (!$split_length)) {
262 do {
263 $c = strlen($string);
264 $parts[] = substr($string, 0, $split_length);
265 $string = substr($string, $split_length);
266 } while ($string !== false);
267 } else {
268 $parts = array($string);
269 }
270 return $parts;
271 }
272}
273
274// #####################################################
275
291class QRcode {
292
297 protected $barcode_array = array();
298
303 protected $version = 0;
304
309 protected $level = QR_ECLEVEL_L;
310
315 protected $hint = QR_MODE_8B;
316
321 protected $casesensitive = true;
322
327 protected $structured = 0;
328
333 protected $data;
334
335 // FrameFiller
336
341 protected $width;
342
347 protected $frame;
348
353 protected $x;
354
359 protected $y;
360
365 protected $dir;
366
371 protected $bit;
372
373 // ---- QRrawcode ----
374
379 protected $datacode = array();
380
385 protected $ecccode = array();
386
391 protected $blocks;
392
397 protected $rsblocks = array(); //of RSblock
398
403 protected $count;
404
409 protected $dataLength;
410
415 protected $eccLength;
416
421 protected $b1;
422
423 // ---- QRmask ----
424
429 protected $runLength = array();
430
431 // ---- QRsplit ----
432
437 protected $dataStr = '';
438
443 protected $items;
444
445 // Reed-Solomon items
446
451 protected $rsitems = array();
452
457 protected $frames = array();
458
463 protected $anTable = array(
464 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
465 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
466 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
467 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, //
468 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
469 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
470 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 //
472 );
473
479 protected $capacity = array(
480 array( 0, 0, 0, array( 0, 0, 0, 0)), //
481 array( 21, 26, 0, array( 7, 10, 13, 17)), // 1
482 array( 25, 44, 7, array( 10, 16, 22, 28)), //
483 array( 29, 70, 7, array( 15, 26, 36, 44)), //
484 array( 33, 100, 7, array( 20, 36, 52, 64)), //
485 array( 37, 134, 7, array( 26, 48, 72, 88)), // 5
486 array( 41, 172, 7, array( 36, 64, 96, 112)), //
487 array( 45, 196, 0, array( 40, 72, 108, 130)), //
488 array( 49, 242, 0, array( 48, 88, 132, 156)), //
489 array( 53, 292, 0, array( 60, 110, 160, 192)), //
490 array( 57, 346, 0, array( 72, 130, 192, 224)), // 10
491 array( 61, 404, 0, array( 80, 150, 224, 264)), //
492 array( 65, 466, 0, array( 96, 176, 260, 308)), //
493 array( 69, 532, 0, array( 104, 198, 288, 352)), //
494 array( 73, 581, 3, array( 120, 216, 320, 384)), //
495 array( 77, 655, 3, array( 132, 240, 360, 432)), // 15
496 array( 81, 733, 3, array( 144, 280, 408, 480)), //
497 array( 85, 815, 3, array( 168, 308, 448, 532)), //
498 array( 89, 901, 3, array( 180, 338, 504, 588)), //
499 array( 93, 991, 3, array( 196, 364, 546, 650)), //
500 array( 97, 1085, 3, array( 224, 416, 600, 700)), // 20
501 array(101, 1156, 4, array( 224, 442, 644, 750)), //
502 array(105, 1258, 4, array( 252, 476, 690, 816)), //
503 array(109, 1364, 4, array( 270, 504, 750, 900)), //
504 array(113, 1474, 4, array( 300, 560, 810, 960)), //
505 array(117, 1588, 4, array( 312, 588, 870, 1050)), // 25
506 array(121, 1706, 4, array( 336, 644, 952, 1110)), //
507 array(125, 1828, 4, array( 360, 700, 1020, 1200)), //
508 array(129, 1921, 3, array( 390, 728, 1050, 1260)), //
509 array(133, 2051, 3, array( 420, 784, 1140, 1350)), //
510 array(137, 2185, 3, array( 450, 812, 1200, 1440)), // 30
511 array(141, 2323, 3, array( 480, 868, 1290, 1530)), //
512 array(145, 2465, 3, array( 510, 924, 1350, 1620)), //
513 array(149, 2611, 3, array( 540, 980, 1440, 1710)), //
514 array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
515 array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
516 array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
517 array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
518 array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
519 array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
520 array(177, 3706, 0, array( 750, 1372, 2040, 2430)) // 40
521 );
522
527 protected $lengthTableBits = array(
528 array(10, 12, 14),
529 array( 9, 11, 13),
530 array( 8, 16, 16),
531 array( 8, 10, 12)
532 );
533
539 protected $eccTable = array(
540 array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), //
541 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1
542 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), //
543 array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)), //
544 array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)), //
545 array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5
546 array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)), //
547 array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)), //
548 array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)), //
549 array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)), //
550 array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), // 10
551 array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)), //
552 array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)), //
553 array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)), //
554 array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)), //
555 array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), // 15
556 array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)), //
557 array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)), //
558 array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)), //
559 array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)), //
560 array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), // 20
561 array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)), //
562 array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)), //
563 array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)), //
564 array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)), //
565 array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
566 array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), //
567 array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)), //
568 array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
569 array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)), //
570 array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
571 array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)), //
572 array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), //
573 array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), //
574 array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), //
575 array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), // 35
576 array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
577 array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), //
578 array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
579 array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), //
580 array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)) // 40
581 );
582
589 protected $alignmentPattern = array(
590 array( 0, 0),
591 array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
592 array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
593 array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
594 array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
595 array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
596 array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
597 array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
598 array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58) // 35-40
599 );
600
607 protected $versionPattern = array(
608 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
609 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
610 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
611 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
612 0x27541, 0x28c69
613 );
614
619 protected $formatInfo = array(
620 array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
621 array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
622 array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
623 array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) //
624 );
625
626
627 // -------------------------------------------------
628 // -------------------------------------------------
629
630
639 public function __construct($code, $eclevel = 'L') {
640 $barcode_array = array();
641 if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
642 return false;
643 }
644 // set error correction level
645 $this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
646 if ($this->level === false) {
647 $this->level = QR_ECLEVEL_L;
648 }
649 if (($this->hint != QR_MODE_8B) AND ($this->hint != QR_MODE_KJ)) {
650 return false;
651 }
652 if (($this->version < 0) OR ($this->version > QRSPEC_VERSION_MAX)) {
653 return false;
654 }
655 $this->items = array();
656 $this->encodeString($code);
657 if (is_null($this->data)) {
658 return false;
659 }
660 $qrTab = $this->binarize($this->data);
661 $size = count($qrTab);
662 $barcode_array['num_rows'] = $size;
663 $barcode_array['num_cols'] = $size;
664 $barcode_array['bcode'] = array();
665 foreach ($qrTab as $line) {
666 $arrAdd = array();
667 foreach (str_split($line) as $char) {
668 $arrAdd[] = ($char=='1')?1:0;
669 }
670 $barcode_array['bcode'][] = $arrAdd;
671 }
672 $this->barcode_array = $barcode_array;
673 }
674
680 public function getBarcodeArray() {
682 }
683
689 protected function binarize($frame) {
690 $len = count($frame);
691 // the frame is square (width = height)
692 foreach ($frame as &$frameLine) {
693 for ($i=0; $i<$len; $i++) {
694 $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
695 }
696 }
697 return $frame;
698 }
699
704 protected function encodeString($string) {
705 $this->dataStr = $string;
706 if (!$this->casesensitive) {
707 $this->toUpper();
708 }
709 $ret = $this->splitString();
710 if ($ret < 0) {
711 return NULL;
712 }
713 $this->encodeMask(-1);
714 }
715
720 protected function encodeMask($mask) {
721 $spec = array(0, 0, 0, 0, 0);
722 $this->datacode = $this->getByteStream($this->items);
723
724 if (is_null($this->datacode)) {
725 return NULL;
726 }
727 $spec = $this->getEccSpec($this->version, $this->level, $spec);
728 $this->b1 = $this->rsBlockNum1($spec);
729 $this->dataLength = $this->rsDataLength($spec);
730 $this->eccLength = $this->rsEccLength($spec);
731 $this->ecccode = array_fill(0, $this->eccLength, 0);
732 $this->blocks = $this->rsBlockNum($spec);
733 $ret = $this->init($spec);
734 if ($ret < 0) {
735 return NULL;
736 }
737 $this->count = 0;
738 $this->width = $this->getWidth($this->version);
739 $this->frame = $this->newFrame($this->version);
740 $this->x = $this->width - 1;
741 $this->y = $this->width - 1;
742 $this->dir = -1;
743 $this->bit = -1;
744 // inteleaved data and ecc codes
745 for ($i=0; $i < ($this->dataLength + $this->eccLength); $i++) {
746 $code = $this->getCode();
747 $bit = 0x80;
748 for ($j=0; $j<8; $j++) {
749 $addr = $this->getNextPosition();
750 $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
751 $bit = $bit >> 1;
752 }
753 }
754 // remainder bits
755 $j = $this->getRemainder($this->version);
756 for ($i=0; $i<$j; $i++) {
757 $addr = $this->getNextPosition();
758 $this->setFrameAt($addr, 0x02);
759 }
760 // masking
761 $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
762 if ($mask < 0) {
763 if (QR_FIND_BEST_MASK) {
764 $masked = $this->mask($this->width, $this->frame, $this->level);
765 } else {
766 $masked = $this->makeMask($this->width, $this->frame, (intval(QR_DEFAULT_MASK) % 8), $this->level);
767 }
768 } else {
769 $masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
770 }
771 if ($masked == NULL) {
772 return NULL;
773 }
774 $this->data = $masked;
775 }
776
777 // - - - - - - - - - - - - - - - - - - - - - - - - -
778
779 // FrameFiller
780
786 protected function setFrameAt($at, $val) {
787 $this->frame[$at['y']][$at['x']] = chr($val);
788 }
789
795 protected function getFrameAt($at) {
796 return ord($this->frame[$at['y']][$at['x']]);
797 }
798
803 protected function getNextPosition() {
804 do {
805 if ($this->bit == -1) {
806 $this->bit = 0;
807 return array('x'=>$this->x, 'y'=>$this->y);
808 }
809 $x = $this->x;
810 $y = $this->y;
812 if ($this->bit == 0) {
813 $x--;
814 $this->bit++;
815 } else {
816 $x++;
817 $y += $this->dir;
818 $this->bit--;
819 }
820 if ($this->dir < 0) {
821 if ($y < 0) {
822 $y = 0;
823 $x -= 2;
824 $this->dir = 1;
825 if ($x == 6) {
826 $x--;
827 $y = 9;
828 }
829 }
830 } else {
831 if ($y == $w) {
832 $y = $w - 1;
833 $x -= 2;
834 $this->dir = -1;
835 if ($x == 6) {
836 $x--;
837 $y -= 8;
838 }
839 }
840 }
841 if (($x < 0) OR ($y < 0)) {
842 return NULL;
843 }
844 $this->x = $x;
845 $this->y = $y;
846 } while(ord($this->frame[$y][$x]) & 0x80);
847 return array('x'=>$x, 'y'=>$y);
848 }
849
850 // - - - - - - - - - - - - - - - - - - - - - - - - -
851
852 // QRrawcode
853
859 protected function init($spec) {
860 $dl = $this->rsDataCodes1($spec);
861 $el = $this->rsEccCodes1($spec);
862 $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
863 $blockNo = 0;
864 $dataPos = 0;
865 $eccPos = 0;
866 $endfor = $this->rsBlockNum1($spec);
867 for ($i=0; $i < $endfor; ++$i) {
868 $ecc = array_slice($this->ecccode, $eccPos);
869 $this->rsblocks[$blockNo] = array();
870 $this->rsblocks[$blockNo]['dataLength'] = $dl;
871 $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
872 $this->rsblocks[$blockNo]['eccLength'] = $el;
873 $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
874 $this->rsblocks[$blockNo]['ecc'] = $ecc;
875 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
876 $dataPos += $dl;
877 $eccPos += $el;
878 $blockNo++;
879 }
880 if ($this->rsBlockNum2($spec) == 0) {
881 return 0;
882 }
883 $dl = $this->rsDataCodes2($spec);
884 $el = $this->rsEccCodes2($spec);
885 $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
886 if ($rs == NULL) {
887 return -1;
888 }
889 $endfor = $this->rsBlockNum2($spec);
890 for ($i=0; $i < $endfor; ++$i) {
891 $ecc = array_slice($this->ecccode, $eccPos);
892 $this->rsblocks[$blockNo] = array();
893 $this->rsblocks[$blockNo]['dataLength'] = $dl;
894 $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
895 $this->rsblocks[$blockNo]['eccLength'] = $el;
896 $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
897 $this->rsblocks[$blockNo]['ecc'] = $ecc;
898 $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
899 $dataPos += $dl;
900 $eccPos += $el;
901 $blockNo++;
902 }
903 return 0;
904 }
905
910 protected function getCode() {
911 if ($this->count < $this->dataLength) {
912 $row = $this->count % $this->blocks;
913 $col = $this->count / $this->blocks;
914 if ($col >= $this->rsblocks[0]['dataLength']) {
915 $row += $this->b1;
916 }
917 $ret = $this->rsblocks[$row]['data'][$col];
918 } elseif ($this->count < $this->dataLength + $this->eccLength) {
919 $row = ($this->count - $this->dataLength) % $this->blocks;
920 $col = ($this->count - $this->dataLength) / $this->blocks;
921 $ret = $this->rsblocks[$row]['ecc'][$col];
922 } else {
923 return 0;
924 }
925 $this->count++;
926 return $ret;
927 }
928
929 // - - - - - - - - - - - - - - - - - - - - - - - - -
930
931 // QRmask
932
942 $blacks = 0;
943 $format = $this->getFormatInfo($mask, $level);
944 for ($i=0; $i<8; ++$i) {
945 if ($format & 1) {
946 $blacks += 2;
947 $v = 0x85;
948 } else {
949 $v = 0x84;
950 }
951 $frame[8][$width - 1 - $i] = chr($v);
952 if ($i < 6) {
953 $frame[$i][8] = chr($v);
954 } else {
955 $frame[$i + 1][8] = chr($v);
956 }
957 $format = $format >> 1;
958 }
959 for ($i=0; $i<7; ++$i) {
960 if ($format & 1) {
961 $blacks += 2;
962 $v = 0x85;
963 } else {
964 $v = 0x84;
965 }
966 $frame[$width - 7 + $i][8] = chr($v);
967 if ($i == 0) {
968 $frame[8][7] = chr($v);
969 } else {
970 $frame[8][6 - $i] = chr($v);
971 }
972 $format = $format >> 1;
973 }
974 return $blacks;
975 }
976
983 protected function mask0($x, $y) {
984 return ($x + $y) & 1;
985 }
986
993 protected function mask1($x, $y) {
994 return ($y & 1);
995 }
996
1003 protected function mask2($x, $y) {
1004 return ($x % 3);
1005 }
1006
1013 protected function mask3($x, $y) {
1014 return ($x + $y) % 3;
1015 }
1016
1023 protected function mask4($x, $y) {
1024 return (((int)($y / 2)) + ((int)($x / 3))) & 1;
1025 }
1026
1033 protected function mask5($x, $y) {
1034 return (($x * $y) & 1) + ($x * $y) % 3;
1035 }
1036
1043 protected function mask6($x, $y) {
1044 return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
1045 }
1046
1053 protected function mask7($x, $y) {
1054 return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
1055 }
1056
1064 protected function generateMaskNo($maskNo, $width, $frame) {
1065 $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
1066 for ($y=0; $y<$width; ++$y) {
1067 for ($x=0; $x<$width; ++$x) {
1068 if (ord($frame[$y][$x]) & 0x80) {
1069 $bitMask[$y][$x] = 0;
1070 } else {
1071 $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
1072 $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
1073 }
1074 }
1075 }
1076 return $bitMask;
1077 }
1078
1088 protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
1089 $b = 0;
1090 $bitMask = array();
1091 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
1092 if ($maskGenOnly) {
1093 return;
1094 }
1095 $d = $s;
1096 for ($y=0; $y<$width; ++$y) {
1097 for ($x=0; $x<$width; ++$x) {
1098 if ($bitMask[$y][$x] == 1) {
1099 $d[$y][$x] = chr(ord($s[$y][$x]) ^ ((int)($bitMask[$y][$x])));
1100 }
1101 $b += (int)(ord($d[$y][$x]) & 1);
1102 }
1103 }
1104 return $b;
1105 }
1106
1115 protected function makeMask($width, $frame, $maskNo, $level) {
1116 $masked = array_fill(0, $width, str_repeat("\0", $width));
1117 $this->makeMaskNo($maskNo, $width, $frame, $masked);
1118 $this->writeFormatInformation($width, $masked, $maskNo, $level);
1119 return $masked;
1120 }
1121
1127 protected function calcN1N3($length) {
1128 $demerit = 0;
1129 for ($i=0; $i<$length; ++$i) {
1130 if ($this->runLength[$i] >= 5) {
1131 $demerit += (N1 + ($this->runLength[$i] - 5));
1132 }
1133 if ($i & 1) {
1134 if (($i >= 3) AND ($i < ($length-2)) AND ($this->runLength[$i] % 3 == 0)) {
1135 $fact = (int)($this->runLength[$i] / 3);
1136 if (($this->runLength[$i-2] == $fact)
1137 AND ($this->runLength[$i-1] == $fact)
1138 AND ($this->runLength[$i+1] == $fact)
1139 AND ($this->runLength[$i+2] == $fact)) {
1140 if (($this->runLength[$i-3] < 0) OR ($this->runLength[$i-3] >= (4 * $fact))) {
1141 $demerit += N3;
1142 } elseif ((($i+3) >= $length) OR ($this->runLength[$i+3] >= (4 * $fact))) {
1143 $demerit += N3;
1144 }
1145 }
1146 }
1147 }
1148 }
1149 return $demerit;
1150 }
1151
1158 protected function evaluateSymbol($width, $frame) {
1159 $head = 0;
1160 $demerit = 0;
1161 for ($y=0; $y<$width; ++$y) {
1162 $head = 0;
1163 $this->runLength[0] = 1;
1164 $frameY = $frame[$y];
1165 if ($y > 0) {
1166 $frameYM = $frame[$y-1];
1167 }
1168 for ($x=0; $x<$width; ++$x) {
1169 if (($x > 0) AND ($y > 0)) {
1170 $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
1171 $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
1172 if (($b22 | ($w22 ^ 1)) & 1) {
1173 $demerit += N2;
1174 }
1175 }
1176 if (($x == 0) AND (ord($frameY[$x]) & 1)) {
1177 $this->runLength[0] = -1;
1178 $head = 1;
1179 $this->runLength[$head] = 1;
1180 } elseif ($x > 0) {
1181 if ((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
1182 $head++;
1183 $this->runLength[$head] = 1;
1184 } else {
1185 $this->runLength[$head]++;
1186 }
1187 }
1188 }
1189 $demerit += $this->calcN1N3($head+1);
1190 }
1191 for ($x=0; $x<$width; ++$x) {
1192 $head = 0;
1193 $this->runLength[0] = 1;
1194 for ($y=0; $y<$width; ++$y) {
1195 if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
1196 $this->runLength[0] = -1;
1197 $head = 1;
1198 $this->runLength[$head] = 1;
1199 } elseif ($y > 0) {
1200 if ((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
1201 $head++;
1202 $this->runLength[$head] = 1;
1203 } else {
1204 $this->runLength[$head]++;
1205 }
1206 }
1207 }
1208 $demerit += $this->calcN1N3($head+1);
1209 }
1210 return $demerit;
1211 }
1212
1220 protected function mask($width, $frame, $level) {
1221 $minDemerit = PHP_INT_MAX;
1222 $bestMaskNum = 0;
1223 $bestMask = array();
1224 $checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
1225 if (QR_FIND_FROM_RANDOM !== false) {
1226 $howManuOut = 8 - (QR_FIND_FROM_RANDOM % 9);
1227 for ($i = 0; $i < $howManuOut; ++$i) {
1228 $remPos = rand (0, count($checked_masks)-1);
1229 unset($checked_masks[$remPos]);
1230 $checked_masks = array_values($checked_masks);
1231 }
1232 }
1233 $bestMask = $frame;
1234 foreach ($checked_masks as $i) {
1235 $mask = array_fill(0, $width, str_repeat("\0", $width));
1236 $demerit = 0;
1237 $blacks = 0;
1238 $blacks = $this->makeMaskNo($i, $width, $frame, $mask);
1239 $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
1240 $blacks = (int)(100 * $blacks / ($width * $width));
1241 $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
1242 $demerit += $this->evaluateSymbol($width, $mask);
1243 if ($demerit < $minDemerit) {
1244 $minDemerit = $demerit;
1245 $bestMask = $mask;
1246 $bestMaskNum = $i;
1247 }
1248 }
1249 return $bestMask;
1250 }
1251
1252 // - - - - - - - - - - - - - - - - - - - - - - - - -
1253
1254 // QRsplit
1255
1262 protected function isdigitat($str, $pos) {
1263 if ($pos >= strlen($str)) {
1264 return false;
1265 }
1266 return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
1267 }
1268
1275 protected function isalnumat($str, $pos) {
1276 if ($pos >= strlen($str)) {
1277 return false;
1278 }
1279 return ($this->lookAnTable(ord($str[$pos])) >= 0);
1280 }
1281
1287 protected function identifyMode($pos) {
1288 if ($pos >= strlen($this->dataStr)) {
1289 return QR_MODE_NL;
1290 }
1291 $c = $this->dataStr[$pos];
1292 if ($this->isdigitat($this->dataStr, $pos)) {
1293 return QR_MODE_NM;
1294 } elseif ($this->isalnumat($this->dataStr, $pos)) {
1295 return QR_MODE_AN;
1296 } elseif ($this->hint == QR_MODE_KJ) {
1297 if ($pos+1 < strlen($this->dataStr)) {
1298 $d = $this->dataStr[$pos+1];
1299 $word = (ord($c) << 8) | ord($d);
1300 if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
1301 return QR_MODE_KJ;
1302 }
1303 }
1304 }
1305 return QR_MODE_8B;
1306 }
1307
1312 protected function eatNum() {
1313 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1314 $p = 0;
1315 while($this->isdigitat($this->dataStr, $p)) {
1316 $p++;
1317 }
1318 $run = $p;
1319 $mode = $this->identifyMode($p);
1320 if ($mode == QR_MODE_8B) {
1321 $dif = $this->estimateBitsModeNum($run) + 4 + $ln
1322 + $this->estimateBitsMode8(1) // + 4 + l8
1323 - $this->estimateBitsMode8($run + 1); // - 4 - l8
1324 if ($dif > 0) {
1325 return $this->eat8();
1326 }
1327 }
1328 if ($mode == QR_MODE_AN) {
1329 $dif = $this->estimateBitsModeNum($run) + 4 + $ln
1330 + $this->estimateBitsModeAn(1) // + 4 + la
1331 - $this->estimateBitsModeAn($run + 1);// - 4 - la
1332 if ($dif > 0) {
1333 return $this->eatAn();
1334 }
1335 }
1336 $this->items = $this->appendNewInputItem($this->items, QR_MODE_NM, $run, str_split($this->dataStr));
1337 return $run;
1338 }
1339
1344 protected function eatAn() {
1345 $la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1346 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1347 $p =1 ;
1348 while($this->isalnumat($this->dataStr, $p)) {
1349 if ($this->isdigitat($this->dataStr, $p)) {
1350 $q = $p;
1351 while($this->isdigitat($this->dataStr, $q)) {
1352 $q++;
1353 }
1354 $dif = $this->estimateBitsModeAn($p) // + 4 + la
1355 + $this->estimateBitsModeNum($q - $p) + 4 + $ln
1356 - $this->estimateBitsModeAn($q); // - 4 - la
1357 if ($dif < 0) {
1358 break;
1359 } else {
1360 $p = $q;
1361 }
1362 } else {
1363 $p++;
1364 }
1365 }
1366 $run = $p;
1367 if (!$this->isalnumat($this->dataStr, $p)) {
1368 $dif = $this->estimateBitsModeAn($run) + 4 + $la
1369 + $this->estimateBitsMode8(1) // + 4 + l8
1370 - $this->estimateBitsMode8($run + 1); // - 4 - l8
1371 if ($dif > 0) {
1372 return $this->eat8();
1373 }
1374 }
1375 $this->items = $this->appendNewInputItem($this->items, QR_MODE_AN, $run, str_split($this->dataStr));
1376 return $run;
1377 }
1378
1383 protected function eatKanji() {
1384 $p = 0;
1385 while($this->identifyMode($p) == QR_MODE_KJ) {
1386 $p += 2;
1387 }
1388 $this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr));
1389 return $run;
1390 }
1391
1396 protected function eat8() {
1397 $la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1398 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1399 $p = 1;
1400 $dataStrLen = strlen($this->dataStr);
1401 while($p < $dataStrLen) {
1402 $mode = $this->identifyMode($p);
1403 if ($mode == QR_MODE_KJ) {
1404 break;
1405 }
1406 if ($mode == QR_MODE_NM) {
1407 $q = $p;
1408 while($this->isdigitat($this->dataStr, $q)) {
1409 $q++;
1410 }
1411 $dif = $this->estimateBitsMode8($p) // + 4 + l8
1412 + $this->estimateBitsModeNum($q - $p) + 4 + $ln
1413 - $this->estimateBitsMode8($q); // - 4 - l8
1414 if ($dif < 0) {
1415 break;
1416 } else {
1417 $p = $q;
1418 }
1419 } elseif ($mode == QR_MODE_AN) {
1420 $q = $p;
1421 while($this->isalnumat($this->dataStr, $q)) {
1422 $q++;
1423 }
1424 $dif = $this->estimateBitsMode8($p) // + 4 + l8
1425 + $this->estimateBitsModeAn($q - $p) + 4 + $la
1426 - $this->estimateBitsMode8($q); // - 4 - l8
1427 if ($dif < 0) {
1428 break;
1429 } else {
1430 $p = $q;
1431 }
1432 } else {
1433 $p++;
1434 }
1435 }
1436 $run = $p;
1437 $this->items = $this->appendNewInputItem($this->items, QR_MODE_8B, $run, str_split($this->dataStr));
1438 return $run;
1439 }
1440
1445 protected function splitString() {
1446 while (strlen($this->dataStr) > 0) {
1447 $mode = $this->identifyMode(0);
1448 switch ($mode) {
1449 case QR_MODE_NM: {
1450 $length = $this->eatNum();
1451 break;
1452 }
1453 case QR_MODE_AN: {
1454 $length = $this->eatAn();
1455 break;
1456 }
1457 case QR_MODE_KJ: {
1458 if ($hint == QR_MODE_KJ) {
1459 $length = $this->eatKanji();
1460 } else {
1461 $length = $this->eat8();
1462 }
1463 break;
1464 }
1465 default: {
1466 $length = $this->eat8();
1467 break;
1468 }
1469 }
1470 if ($length == 0) {
1471 return 0;
1472 }
1473 if ($length < 0) {
1474 return -1;
1475 }
1476 $this->dataStr = substr($this->dataStr, $length);
1477 }
1478 return 0;
1479 }
1480
1484 protected function toUpper() {
1485 $stringLen = strlen($this->dataStr);
1486 $p = 0;
1487 while ($p < $stringLen) {
1488 $mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
1489 if ($mode == QR_MODE_KJ) {
1490 $p += 2;
1491 } else {
1492 if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
1493 $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
1494 }
1495 $p++;
1496 }
1497 }
1498 return $this->dataStr;
1499 }
1500
1501 // - - - - - - - - - - - - - - - - - - - - - - - - -
1502
1503 // QRinputItem
1504
1513 protected function newInputItem($mode, $size, $data, $bstream=null) {
1514 $setData = array_slice($data, 0, $size);
1515 if (count($setData) < $size) {
1516 $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
1517 }
1518 if (!$this->check($mode, $size, $setData)) {
1519 return NULL;
1520 }
1521 $inputitem = array();
1522 $inputitem['mode'] = $mode;
1523 $inputitem['size'] = $size;
1524 $inputitem['data'] = $setData;
1525 $inputitem['bstream'] = $bstream;
1526 return $inputitem;
1527 }
1528
1535 protected function encodeModeNum($inputitem, $version) {
1536 $words = (int)($inputitem['size'] / 3);
1537 $inputitem['bstream'] = array();
1538 $val = 0x1;
1539 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1540 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_NM, $version), $inputitem['size']);
1541 for ($i=0; $i < $words; ++$i) {
1542 $val = (ord($inputitem['data'][$i*3 ]) - ord('0')) * 100;
1543 $val += (ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
1544 $val += (ord($inputitem['data'][$i*3+2]) - ord('0'));
1545 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
1546 }
1547 if ($inputitem['size'] - $words * 3 == 1) {
1548 $val = ord($inputitem['data'][$words*3]) - ord('0');
1549 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1550 } elseif (($inputitem['size'] - ($words * 3)) == 2) {
1551 $val = (ord($inputitem['data'][$words*3 ]) - ord('0')) * 10;
1552 $val += (ord($inputitem['data'][$words*3+1]) - ord('0'));
1553 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
1554 }
1555 return $inputitem;
1556 }
1557
1564 protected function encodeModeAn($inputitem, $version) {
1565 $words = (int)($inputitem['size'] / 2);
1566 $inputitem['bstream'] = array();
1567 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
1568 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_AN, $version), $inputitem['size']);
1569 for ($i=0; $i < $words; ++$i) {
1570 $val = (int)($this->lookAnTable(ord($inputitem['data'][$i*2])) * 45);
1571 $val += (int)($this->lookAnTable(ord($inputitem['data'][($i*2)+1])));
1572 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
1573 }
1574 if ($inputitem['size'] & 1) {
1575 $val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
1576 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
1577 }
1578 return $inputitem;
1579 }
1580
1587 protected function encodeMode8($inputitem, $version) {
1588 $inputitem['bstream'] = array();
1589 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
1590 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_8B, $version), $inputitem['size']);
1591 for ($i=0; $i < $inputitem['size']; ++$i) {
1592 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
1593 }
1594 return $inputitem;
1595 }
1596
1603 protected function encodeModeKanji($inputitem, $version) {
1604 $inputitem['bstream'] = array();
1605 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
1606 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
1607 for ($i=0; $i<$inputitem['size']; $i+=2) {
1608 $val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
1609 if ($val <= 0x9ffc) {
1610 $val -= 0x8140;
1611 } else {
1612 $val -= 0xc140;
1613 }
1614 $h = ($val >> 8) * 0xc0;
1615 $val = ($val & 0xff) + $h;
1616 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
1617 }
1618 return $inputitem;
1619 }
1620
1626 protected function encodeModeStructure($inputitem) {
1627 $inputitem['bstream'] = array();
1628 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
1629 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
1630 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
1631 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
1632 return $inputitem;
1633 }
1634
1641 protected function encodeBitStream($inputitem, $version) {
1642 $inputitem['bstream'] = array();
1643 $words = $this->maximumWords($inputitem['mode'], $version);
1644 if ($inputitem['size'] > $words) {
1645 $st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
1646 $st2 = $this->newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
1647 $st1 = $this->encodeBitStream($st1, $version);
1648 $st2 = $this->encodeBitStream($st2, $version);
1649 $inputitem['bstream'] = array();
1650 $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
1651 $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
1652 } else {
1653 switch($inputitem['mode']) {
1654 case QR_MODE_NM: {
1655 $inputitem = $this->encodeModeNum($inputitem, $version);
1656 break;
1657 }
1658 case QR_MODE_AN: {
1659 $inputitem = $this->encodeModeAn($inputitem, $version);
1660 break;
1661 }
1662 case QR_MODE_8B: {
1663 $inputitem = $this->encodeMode8($inputitem, $version);
1664 break;
1665 }
1666 case QR_MODE_KJ: {
1667 $inputitem = $this->encodeModeKanji($inputitem, $version);
1668 break;
1669 }
1670 case QR_MODE_ST: {
1671 $inputitem = $this->encodeModeStructure($inputitem);
1672 break;
1673 }
1674 default: {
1675 break;
1676 }
1677 }
1678 }
1679 return $inputitem;
1680 }
1681
1682 // - - - - - - - - - - - - - - - - - - - - - - - - -
1683
1684 // QRinput
1685
1696 protected function appendNewInputItem($items, $mode, $size, $data) {
1697 $newitem = $this->newInputItem($mode, $size, $data);
1698 if (!empty($newitem)) {
1699 $items[] = $newitem;
1700 }
1701 return $items;
1702 }
1703
1712 protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
1713 if ($size > MAX_STRUCTURED_SYMBOLS) {
1714 return -1;
1715 }
1716 if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
1717 return -1;
1718 }
1719 $buf = array($size, $index, $parity);
1720 $entry = $this->newInputItem(QR_MODE_ST, 3, buf);
1721 array_unshift($items, $entry);
1722 return $items;
1723 }
1724
1730 protected function calcParity($items) {
1731 $parity = 0;
1732 foreach ($items as $item) {
1733 if ($item['mode'] != QR_MODE_ST) {
1734 for ($i=$item['size']-1; $i>=0; --$i) {
1735 $parity ^= $item['data'][$i];
1736 }
1737 }
1738 }
1739 return $parity;
1740 }
1741
1748 protected function checkModeNum($size, $data) {
1749 for ($i=0; $i<$size; ++$i) {
1750 if ((ord($data[$i]) < ord('0')) OR (ord($data[$i]) > ord('9'))){
1751 return false;
1752 }
1753 }
1754 return true;
1755 }
1756
1762 protected function lookAnTable($c) {
1763 return (($c > 127)?-1:$this->anTable[$c]);
1764 }
1765
1772 protected function checkModeAn($size, $data) {
1773 for ($i=0; $i<$size; ++$i) {
1774 if ($this->lookAnTable(ord($data[$i])) == -1) {
1775 return false;
1776 }
1777 }
1778 return true;
1779 }
1780
1786 protected function estimateBitsModeNum($size) {
1787 $w = (int)($size / 3);
1788 $bits = ($w * 10);
1789 switch($size - ($w * 3)) {
1790 case 1: {
1791 $bits += 4;
1792 break;
1793 }
1794 case 2: {
1795 $bits += 7;
1796 break;
1797 }
1798 }
1799 return $bits;
1800 }
1801
1807 protected function estimateBitsModeAn($size) {
1808 $bits = (int)($size * 5.5); // (size / 2 ) * 11
1809 if ($size & 1) {
1810 $bits += 6;
1811 }
1812 return $bits;
1813 }
1814
1820 protected function estimateBitsMode8($size) {
1821 return (int)($size * 8);
1822 }
1823
1829 protected function estimateBitsModeKanji($size) {
1830 return (int)($size * 6.5); // (size / 2 ) * 13
1831 }
1832
1839 protected function checkModeKanji($size, $data) {
1840 if ($size & 1) {
1841 return false;
1842 }
1843 for ($i=0; $i<$size; $i+=2) {
1844 $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
1845 if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
1846 return false;
1847 }
1848 }
1849 return true;
1850 }
1851
1859 protected function check($mode, $size, $data) {
1860 if ($size <= 0) {
1861 return false;
1862 }
1863 switch($mode) {
1864 case QR_MODE_NM: {
1865 return $this->checkModeNum($size, $data);
1866 }
1867 case QR_MODE_AN: {
1868 return $this->checkModeAn($size, $data);
1869 }
1870 case QR_MODE_KJ: {
1871 return $this->checkModeKanji($size, $data);
1872 }
1873 case QR_MODE_8B: {
1874 return true;
1875 }
1876 case QR_MODE_ST: {
1877 return true;
1878 }
1879 default: {
1880 break;
1881 }
1882 }
1883 return false;
1884 }
1885
1893 $bits = 0;
1894 if ($version == 0) {
1895 $version = 1;
1896 }
1897 foreach ($items as $item) {
1898 switch($item['mode']) {
1899 case QR_MODE_NM: {
1900 $bits = $this->estimateBitsModeNum($item['size']);
1901 break;
1902 }
1903 case QR_MODE_AN: {
1904 $bits = $this->estimateBitsModeAn($item['size']);
1905 break;
1906 }
1907 case QR_MODE_8B: {
1908 $bits = $this->estimateBitsMode8($item['size']);
1909 break;
1910 }
1911 case QR_MODE_KJ: {
1912 $bits = $this->estimateBitsModeKanji($item['size']);
1913 break;
1914 }
1915 case QR_MODE_ST: {
1916 return STRUCTURE_HEADER_BITS;
1917 }
1918 default: {
1919 return 0;
1920 }
1921 }
1922 $l = $this->lengthIndicator($item['mode'], $version);
1923 $m = 1 << $l;
1924 $num = (int)(($item['size'] + $m - 1) / $m);
1925 $bits += $num * (4 + $l);
1926 }
1927 return $bits;
1928 }
1929
1935 protected function estimateVersion($items) {
1936 $version = 0;
1937 $prev = 0;
1938 do {
1939 $prev = $version;
1940 $bits = $this->estimateBitStreamSize($items, $prev);
1941 $version = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1942 if ($version < 0) {
1943 return -1;
1944 }
1945 } while ($version > $prev);
1946 return $version;
1947 }
1948
1956 protected function lengthOfCode($mode, $version, $bits) {
1957 $payload = $bits - 4 - $this->lengthIndicator($mode, $version);
1958 switch($mode) {
1959 case QR_MODE_NM: {
1960 $chunks = (int)($payload / 10);
1961 $remain = $payload - $chunks * 10;
1962 $size = $chunks * 3;
1963 if ($remain >= 7) {
1964 $size += 2;
1965 } elseif ($remain >= 4) {
1966 $size += 1;
1967 }
1968 break;
1969 }
1970 case QR_MODE_AN: {
1971 $chunks = (int)($payload / 11);
1972 $remain = $payload - $chunks * 11;
1973 $size = $chunks * 2;
1974 if ($remain >= 6) {
1975 ++$size;
1976 }
1977 break;
1978 }
1979 case QR_MODE_8B: {
1980 $size = (int)($payload / 8);
1981 break;
1982 }
1983 case QR_MODE_KJ: {
1984 $size = (int)(($payload / 13) * 2);
1985 break;
1986 }
1987 case QR_MODE_ST: {
1988 $size = (int)($payload / 8);
1989 break;
1990 }
1991 default: {
1992 $size = 0;
1993 break;
1994 }
1995 }
1996 $maxsize = $this->maximumWords($mode, $version);
1997 if ($size < 0) {
1998 $size = 0;
1999 }
2000 if ($size > $maxsize) {
2001 $size = $maxsize;
2002 }
2003 return $size;
2004 }
2005
2011 protected function createBitStream($items) {
2012 $total = 0;
2013 foreach ($items as $key => $item) {
2014 $items[$key] = $this->encodeBitStream($item, $this->version);
2015 $bits = count($items[$key]['bstream']);
2016 $total += $bits;
2017 }
2018 return array($items, $total);
2019 }
2020
2026 protected function convertData($items) {
2027 $ver = $this->estimateVersion($items);
2028 if ($ver > $this->version) {
2029 $this->version = $ver;
2030 }
2031 while (true) {
2032 $cbs = $this->createBitStream($items);
2033 $items = $cbs[0];
2034 $bits = $cbs[1];
2035 if ($bits < 0) {
2036 return -1;
2037 }
2038 $ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
2039 if ($ver < 0) {
2040 return -1;
2041 } elseif ($ver > $this->version) {
2042 $this->version = $ver;
2043 } else {
2044 break;
2045 }
2046 }
2047 return $items;
2048 }
2049
2055 protected function appendPaddingBit($bstream) {
2056 if (is_null($bstream)) {
2057 return null;
2058 }
2059 $bits = count($bstream);
2060 $maxwords = $this->getDataLength($this->version, $this->level);
2061 $maxbits = $maxwords * 8;
2062 if ($maxbits == $bits) {
2063 return $bstream;
2064 }
2065 if ($maxbits - $bits < 5) {
2066 return $this->appendNum($bstream, $maxbits - $bits, 0);
2067 }
2068 $bits += 4;
2069 $words = (int)(($bits + 7) / 8);
2070 $padding = array();
2071 $padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0);
2072 $padlen = $maxwords - $words;
2073 if ($padlen > 0) {
2074 $padbuf = array();
2075 for ($i=0; $i<$padlen; ++$i) {
2076 $padbuf[$i] = ($i&1)?0x11:0xec;
2077 }
2078 $padding = $this->appendBytes($padding, $padlen, $padbuf);
2079 }
2080 return $this->appendBitstream($bstream, $padding);
2081 }
2082
2088 protected function mergeBitStream($items) {
2089 $items = $this->convertData($items);
2090 if (!is_array($items)) {
2091 return null;
2092 }
2093 $bstream = array();
2094 foreach ($items as $item) {
2095 $bstream = $this->appendBitstream($bstream, $item['bstream']);
2096 }
2097 return $bstream;
2098 }
2099
2105 protected function getBitStream($items) {
2106 $bstream = $this->mergeBitStream($items);
2107 return $this->appendPaddingBit($bstream);
2108 }
2109
2115 protected function getByteStream($items) {
2116 $bstream = $this->getBitStream($items);
2117 return $this->bitstreamToByte($bstream);
2118 }
2119
2120 // - - - - - - - - - - - - - - - - - - - - - - - - -
2121
2122 // QRbitstream
2123
2129 protected function allocate($setLength) {
2130 return array_fill(0, $setLength, 0);
2131 }
2132
2139 protected function newFromNum($bits, $num) {
2140 $bstream = $this->allocate($bits);
2141 $mask = 1 << ($bits - 1);
2142 for ($i=0; $i<$bits; ++$i) {
2143 if ($num & $mask) {
2144 $bstream[$i] = 1;
2145 } else {
2146 $bstream[$i] = 0;
2147 }
2148 $mask = $mask >> 1;
2149 }
2150 return $bstream;
2151 }
2152
2159 protected function newFromBytes($size, $data) {
2160 $bstream = $this->allocate($size * 8);
2161 $p=0;
2162 for ($i=0; $i<$size; ++$i) {
2163 $mask = 0x80;
2164 for ($j=0; $j<8; ++$j) {
2165 if ($data[$i] & $mask) {
2166 $bstream[$p] = 1;
2167 } else {
2168 $bstream[$p] = 0;
2169 }
2170 $p++;
2171 $mask = $mask >> 1;
2172 }
2173 }
2174 return $bstream;
2175 }
2176
2183 protected function appendBitstream($bitstream, $append) {
2184 if ((!is_array($append)) OR (count($append) == 0)) {
2185 return $bitstream;
2186 }
2187 if (count($bitstream) == 0) {
2188 return $append;
2189 }
2190 return array_values(array_merge($bitstream, $append));
2191 }
2192
2200 protected function appendNum($bitstream, $bits, $num) {
2201 if ($bits == 0) {
2202 return 0;
2203 }
2204 $b = $this->newFromNum($bits, $num);
2205 return $this->appendBitstream($bitstream, $b);
2206 }
2207
2215 protected function appendBytes($bitstream, $size, $data) {
2216 if ($size == 0) {
2217 return 0;
2218 }
2219 $b = $this->newFromBytes($size, $data);
2220 return $this->appendBitstream($bitstream, $b);
2221 }
2222
2228 protected function bitstreamToByte($bstream) {
2229 if (is_null($bstream)) {
2230 return null;
2231 }
2232 $size = count($bstream);
2233 if ($size == 0) {
2234 return array();
2235 }
2236 $data = array_fill(0, (int)(($size + 7) / 8), 0);
2237 $bytes = (int)($size / 8);
2238 $p = 0;
2239 for ($i=0; $i<$bytes; $i++) {
2240 $v = 0;
2241 for ($j=0; $j<8; $j++) {
2242 $v = $v << 1;
2243 $v |= $bstream[$p];
2244 $p++;
2245 }
2246 $data[$i] = $v;
2247 }
2248 if ($size & 7) {
2249 $v = 0;
2250 for ($j=0; $j<($size & 7); $j++) {
2251 $v = $v << 1;
2252 $v |= $bstream[$p];
2253 $p++;
2254 }
2255 $data[$bytes] = $v;
2256 }
2257 return $data;
2258 }
2259
2260 // - - - - - - - - - - - - - - - - - - - - - - - - -
2261
2262 // QRspec
2263
2273 protected function qrstrset($srctab, $x, $y, $repl, $replLen=false) {
2274 $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
2275 return $srctab;
2276 }
2277
2284 protected function getDataLength($version, $level) {
2285 return $this->capacity[$version][QRCAP_WORDS] - $this->capacity[$version][QRCAP_EC][$level];
2286 }
2287
2294 protected function getECCLength($version, $level){
2295 return $this->capacity[$version][QRCAP_EC][$level];
2296 }
2297
2303 protected function getWidth($version) {
2304 return $this->capacity[$version][QRCAP_WIDTH];
2305 }
2306
2312 protected function getRemainder($version) {
2313 return $this->capacity[$version][QRCAP_REMINDER];
2314 }
2315
2322 protected function getMinimumVersion($size, $level) {
2323 for ($i = 1; $i <= QRSPEC_VERSION_MAX; ++$i) {
2324 $words = ($this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level]);
2325 if ($words >= $size) {
2326 return $i;
2327 }
2328 }
2329 // the size of input data is greater than QR capacity, try to lover the error correction mode
2330 return -1;
2331 }
2332
2339 protected function lengthIndicator($mode, $version) {
2340 if ($mode == QR_MODE_ST) {
2341 return 0;
2342 }
2343 if ($version <= 9) {
2344 $l = 0;
2345 } elseif ($version <= 26) {
2346 $l = 1;
2347 } else {
2348 $l = 2;
2349 }
2350 return $this->lengthTableBits[$mode][$l];
2351 }
2352
2359 protected function maximumWords($mode, $version) {
2360 if ($mode == QR_MODE_ST) {
2361 return 3;
2362 }
2363 if ($version <= 9) {
2364 $l = 0;
2365 } else if ($version <= 26) {
2366 $l = 1;
2367 } else {
2368 $l = 2;
2369 }
2370 $bits = $this->lengthTableBits[$mode][$l];
2371 $words = (1 << $bits) - 1;
2372 if ($mode == QR_MODE_KJ) {
2373 $words *= 2; // the number of bytes is required
2374 }
2375 return $words;
2376 }
2377
2385 protected function getEccSpec($version, $level, $spec) {
2386 if (count($spec) < 5) {
2387 $spec = array(0, 0, 0, 0, 0);
2388 }
2389 $b1 = $this->eccTable[$version][$level][0];
2390 $b2 = $this->eccTable[$version][$level][1];
2392 $ecc = $this->getECCLength($version, $level);
2393 if ($b2 == 0) {
2394 $spec[0] = $b1;
2395 $spec[1] = (int)($data / $b1);
2396 $spec[2] = (int)($ecc / $b1);
2397 $spec[3] = 0;
2398 $spec[4] = 0;
2399 } else {
2400 $spec[0] = $b1;
2401 $spec[1] = (int)($data / ($b1 + $b2));
2402 $spec[2] = (int)($ecc / ($b1 + $b2));
2403 $spec[3] = $b2;
2404 $spec[4] = $spec[1] + 1;
2405 }
2406 return $spec;
2407 }
2408
2416 protected function putAlignmentMarker($frame, $ox, $oy) {
2417 $finder = array(
2418 "\xa1\xa1\xa1\xa1\xa1",
2419 "\xa1\xa0\xa0\xa0\xa1",
2420 "\xa1\xa0\xa1\xa0\xa1",
2421 "\xa1\xa0\xa0\xa0\xa1",
2422 "\xa1\xa1\xa1\xa1\xa1"
2423 );
2424 $yStart = $oy - 2;
2425 $xStart = $ox - 2;
2426 for ($y=0; $y < 5; $y++) {
2427 $frame = $this->qrstrset($frame, $xStart, $yStart+$y, $finder[$y]);
2428 }
2429 return $frame;
2430 }
2431
2440 if ($version < 2) {
2441 return $frame;
2442 }
2443 $d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0];
2444 if ($d < 0) {
2445 $w = 2;
2446 } else {
2447 $w = (int)(($width - $this->alignmentPattern[$version][0]) / $d + 2);
2448 }
2449 if ($w * $w - 3 == 1) {
2450 $x = $this->alignmentPattern[$version][0];
2451 $y = $this->alignmentPattern[$version][0];
2452 $frame = $this->putAlignmentMarker($frame, $x, $y);
2453 return $frame;
2454 }
2455 $cx = $this->alignmentPattern[$version][0];
2456 $wo = $w - 1;
2457 for ($x=1; $x < $wo; ++$x) {
2458 $frame = $this->putAlignmentMarker($frame, 6, $cx);
2459 $frame = $this->putAlignmentMarker($frame, $cx, 6);
2460 $cx += $d;
2461 }
2462 $cy = $this->alignmentPattern[$version][0];
2463 for ($y=0; $y < $wo; ++$y) {
2464 $cx = $this->alignmentPattern[$version][0];
2465 for ($x=0; $x < $wo; ++$x) {
2466 $frame = $this->putAlignmentMarker($frame, $cx, $cy);
2467 $cx += $d;
2468 }
2469 $cy += $d;
2470 }
2471 return $frame;
2472 }
2473
2479 protected function getVersionPattern($version) {
2480 if (($version < 7) OR ($version > QRSPEC_VERSION_MAX)) {
2481 return 0;
2482 }
2483 return $this->versionPattern[($version - 7)];
2484 }
2485
2492 protected function getFormatInfo($mask, $level) {
2493 if (($mask < 0) OR ($mask > 7)) {
2494 return 0;
2495 }
2496 if (($level < 0) OR ($level > 3)) {
2497 return 0;
2498 }
2499 return $this->formatInfo[$level][$mask];
2500 }
2501
2509 protected function putFinderPattern($frame, $ox, $oy) {
2510 $finder = array(
2511 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
2512 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2513 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2514 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2515 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2516 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2517 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
2518 );
2519 for ($y=0; $y < 7; $y++) {
2520 $frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
2521 }
2522 return $frame;
2523 }
2524
2530 protected function createFrame($version) {
2531 $width = $this->capacity[$version][QRCAP_WIDTH];
2532 $frameLine = str_repeat ("\0", $width);
2533 $frame = array_fill(0, $width, $frameLine);
2534 // Finder pattern
2535 $frame = $this->putFinderPattern($frame, 0, 0);
2536 $frame = $this->putFinderPattern($frame, $width - 7, 0);
2537 $frame = $this->putFinderPattern($frame, 0, $width - 7);
2538 // Separator
2539 $yOffset = $width - 7;
2540 for ($y=0; $y < 7; ++$y) {
2541 $frame[$y][7] = "\xc0";
2542 $frame[$y][$width - 8] = "\xc0";
2543 $frame[$yOffset][7] = "\xc0";
2544 ++$yOffset;
2545 }
2546 $setPattern = str_repeat("\xc0", 8);
2547 $frame = $this->qrstrset($frame, 0, 7, $setPattern);
2548 $frame = $this->qrstrset($frame, $width-8, 7, $setPattern);
2549 $frame = $this->qrstrset($frame, 0, $width - 8, $setPattern);
2550 // Format info
2551 $setPattern = str_repeat("\x84", 9);
2552 $frame = $this->qrstrset($frame, 0, 8, $setPattern);
2553 $frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8);
2554 $yOffset = $width - 8;
2555 for ($y=0; $y < 8; ++$y,++$yOffset) {
2556 $frame[$y][8] = "\x84";
2557 $frame[$yOffset][8] = "\x84";
2558 }
2559 // Timing pattern
2560 $wo = $width - 15;
2561 for ($i=1; $i < $wo; ++$i) {
2562 $frame[6][7+$i] = chr(0x90 | ($i & 1));
2563 $frame[7+$i][6] = chr(0x90 | ($i & 1));
2564 }
2565 // Alignment pattern
2567 // Version information
2568 if ($version >= 7) {
2569 $vinf = $this->getVersionPattern($version);
2570 $v = $vinf;
2571 for ($x=0; $x<6; ++$x) {
2572 for ($y=0; $y<3; ++$y) {
2573 $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
2574 $v = $v >> 1;
2575 }
2576 }
2577 $v = $vinf;
2578 for ($y=0; $y<6; ++$y) {
2579 for ($x=0; $x<3; ++$x) {
2580 $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
2581 $v = $v >> 1;
2582 }
2583 }
2584 }
2585 // and a little bit...
2586 $frame[$width - 8][8] = "\x81";
2587 return $frame;
2588 }
2589
2595 protected function newFrame($version) {
2596 if (($version < 1) OR ($version > QRSPEC_VERSION_MAX)) {
2597 return NULL;
2598 }
2599 if (!isset($this->frames[$version])) {
2600 $this->frames[$version] = $this->createFrame($version);
2601 }
2602 if (is_null($this->frames[$version])) {
2603 return NULL;
2604 }
2605 return $this->frames[$version];
2606 }
2607
2613 protected function rsBlockNum($spec) {
2614 return ($spec[0] + $spec[3]);
2615 }
2616
2622 protected function rsBlockNum1($spec) {
2623 return $spec[0];
2624 }
2625
2631 protected function rsDataCodes1($spec) {
2632 return $spec[1];
2633 }
2634
2640 protected function rsEccCodes1($spec) {
2641 return $spec[2];
2642 }
2643
2649 protected function rsBlockNum2($spec) {
2650 return $spec[3];
2651 }
2652
2658 protected function rsDataCodes2($spec) {
2659 return $spec[4];
2660 }
2661
2667 protected function rsEccCodes2($spec) {
2668 return $spec[2];
2669 }
2670
2676 protected function rsDataLength($spec) {
2677 return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
2678 }
2679
2685 protected function rsEccLength($spec) {
2686 return ($spec[0] + $spec[3]) * $spec[2];
2687 }
2688
2689 // - - - - - - - - - - - - - - - - - - - - - - - - -
2690
2691 // QRrs
2692
2703 protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2704 foreach ($this->rsitems as $rs) {
2705 if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
2706 OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
2707 continue;
2708 }
2709 return $rs;
2710 }
2711 $rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2712 array_unshift($this->rsitems, $rs);
2713 return $rs;
2714 }
2715
2716 // - - - - - - - - - - - - - - - - - - - - - - - - -
2717
2718 // QRrsItem
2719
2726 protected function modnn($rs, $x) {
2727 while ($x >= $rs['nn']) {
2728 $x -= $rs['nn'];
2729 $x = ($x >> $rs['mm']) + ($x & $rs['nn']);
2730 }
2731 return $x;
2732 }
2733
2744 protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2745 // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
2746 $rs = null;
2747 // Check parameter ranges
2748 if (($symsize < 0) OR ($symsize > 8)) {
2749 return $rs;
2750 }
2751 if (($fcr < 0) OR ($fcr >= (1<<$symsize))) {
2752 return $rs;
2753 }
2754 if (($prim <= 0) OR ($prim >= (1<<$symsize))) {
2755 return $rs;
2756 }
2757 if (($nroots < 0) OR ($nroots >= (1<<$symsize))) {
2758 return $rs;
2759 }
2760 if (($pad < 0) OR ($pad >= ((1<<$symsize) -1 - $nroots))) {
2761 return $rs;
2762 }
2763 $rs = array();
2764 $rs['mm'] = $symsize;
2765 $rs['nn'] = (1 << $symsize) - 1;
2766 $rs['pad'] = $pad;
2767 $rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
2768 $rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
2769 // PHP style macro replacement ;)
2770 $NN =& $rs['nn'];
2771 $A0 =& $NN;
2772 // Generate Galois field lookup tables
2773 $rs['index_of'][0] = $A0; // log(zero) = -inf
2774 $rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
2775 $sr = 1;
2776 for ($i=0; $i<$rs['nn']; ++$i) {
2777 $rs['index_of'][$sr] = $i;
2778 $rs['alpha_to'][$i] = $sr;
2779 $sr <<= 1;
2780 if ($sr & (1 << $symsize)) {
2781 $sr ^= $gfpoly;
2782 }
2783 $sr &= $rs['nn'];
2784 }
2785 if ($sr != 1) {
2786 // field generator polynomial is not primitive!
2787 return NULL;
2788 }
2789 // Form RS code generator polynomial from its roots
2790 $rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
2791 $rs['fcr'] = $fcr;
2792 $rs['prim'] = $prim;
2793 $rs['nroots'] = $nroots;
2794 $rs['gfpoly'] = $gfpoly;
2795 // Find prim-th root of 1, used in decoding
2796 for ($iprim=1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
2797 ; // intentional empty-body loop!
2798 }
2799 $rs['iprim'] = (int)($iprim / $prim);
2800 $rs['genpoly'][0] = 1;
2801 for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
2802 $rs['genpoly'][$i+1] = 1;
2803 // Multiply rs->genpoly[] by @**(root + x)
2804 for ($j = $i; $j > 0; --$j) {
2805 if ($rs['genpoly'][$j] != 0) {
2806 $rs['genpoly'][$j] = $rs['genpoly'][$j-1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
2807 } else {
2808 $rs['genpoly'][$j] = $rs['genpoly'][$j-1];
2809 }
2810 }
2811 // rs->genpoly[0] can never be zero
2812 $rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
2813 }
2814 // convert rs->genpoly[] to index form for quicker encoding
2815 for ($i = 0; $i <= $nroots; ++$i) {
2816 $rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
2817 }
2818 return $rs;
2819 }
2820
2828 protected function encode_rs_char($rs, $data, $parity) {
2829 $MM =& $rs['mm']; // bits per symbol
2830 $NN =& $rs['nn']; // the total number of symbols in a RS block
2831 $ALPHA_TO =& $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form
2832 $INDEX_OF =& $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form
2833 $GENPOLY =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
2834 $NROOTS =& $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block
2835 $FCR =& $rs['fcr']; // first consecutive root, index form
2836 $PRIM =& $rs['prim']; // primitive element, index form
2837 $IPRIM =& $rs['iprim']; // prim-th root of 1, index form
2838 $PAD =& $rs['pad']; // the number of pad symbols in a block
2839 $A0 =& $NN;
2840 $parity = array_fill(0, $NROOTS, 0);
2841 for ($i=0; $i < ($NN - $NROOTS - $PAD); $i++) {
2842 $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2843 if ($feedback != $A0) {
2844 // feedback term is non-zero
2845 // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2846 // always be for the polynomials constructed by init_rs()
2847 $feedback = $this->modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
2848 for ($j=1; $j < $NROOTS; ++$j) {
2849 $parity[$j] ^= $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
2850 }
2851 }
2852 // Shift
2853 array_shift($parity);
2854 if ($feedback != $A0) {
2855 array_push($parity, $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[0])]);
2856 } else {
2857 array_push($parity, 0);
2858 }
2859 }
2860 return $parity;
2861 }
2862
2863} // end QRcode class
2864
2865//============================================================+
2866// END OF FILE
2867//============================================================+
$size
Definition: RandomTest.php:79
global $l
Definition: afr.php:30
Class to create QR-code arrays for TCPDF class.
Definition: qrcode.php:291
$frame
Frame.
Definition: qrcode.php:347
lookAnTable($c)
Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
Definition: qrcode.php:1762
getFormatInfo($mask, $level)
Return BCH encoded format information pattern.
Definition: qrcode.php:2492
$eccTable
Array Table of the error correction code (Reed-Solomon block).
Definition: qrcode.php:539
getByteStream($items)
Pack all bit streams padding bits into a byte array.
Definition: qrcode.php:2115
$level
Levels of error correction.
Definition: qrcode.php:309
$anTable
Alphabet-numeric convesion table.
Definition: qrcode.php:463
putAlignmentMarker($frame, $ox, $oy)
Put an alignment marker.
Definition: qrcode.php:2416
mask3($x, $y)
mask3
Definition: qrcode.php:1013
$datacode
Data code.
Definition: qrcode.php:379
getEccSpec($version, $level, $spec)
Return an array of ECC specification.
Definition: qrcode.php:2385
isalnumat($str, $pos)
Return true if the character at specified position is an alphanumeric character.
Definition: qrcode.php:1275
$capacity
Array Table of the capacity of symbols.
Definition: qrcode.php:479
encode_rs_char($rs, $data, $parity)
Encode a Reed-Solomon codec and returns the parity array.
Definition: qrcode.php:2828
estimateBitsMode8($size)
estimateBitsMode8
Definition: qrcode.php:1820
bitstreamToByte($bstream)
Convert bitstream to bytes.
Definition: qrcode.php:2228
estimateBitsModeAn($size)
estimateBitsModeAn
Definition: qrcode.php:1807
$b1
Value b1.
Definition: qrcode.php:421
estimateVersion($items)
estimateVersion
Definition: qrcode.php:1935
$frames
Array of frames.
Definition: qrcode.php:457
setFrameAt($at, $val)
Set frame value at specified position.
Definition: qrcode.php:786
lengthOfCode($mode, $version, $bits)
lengthOfCode
Definition: qrcode.php:1956
rsBlockNum($spec)
Return block number 0.
Definition: qrcode.php:2613
$rsitems
Reed-Solomon items.
Definition: qrcode.php:451
identifyMode($pos)
identifyMode
Definition: qrcode.php:1287
$eccLength
Error correction length.
Definition: qrcode.php:415
getDataLength($version, $level)
Return maximum data code length (bytes) for the version.
Definition: qrcode.php:2284
putFinderPattern($frame, $ox, $oy)
Put a finder pattern.
Definition: qrcode.php:2509
$x
X position of bit.
Definition: qrcode.php:353
calcN1N3($length)
calcN1N3
Definition: qrcode.php:1127
appendBytes($bitstream, $size, $data)
Append one bitstream created from bytes to another.
Definition: qrcode.php:2215
$runLength
Run length.
Definition: qrcode.php:429
maximumWords($mode, $version)
Return the maximum length for the mode and version.
Definition: qrcode.php:2359
rsBlockNum2($spec)
Return block number 2.
Definition: qrcode.php:2649
checkModeAn($size, $data)
checkModeAn
Definition: qrcode.php:1772
$alignmentPattern
Array Positions of alignment patterns.
Definition: qrcode.php:589
__construct($code, $eclevel='L')
This is the class constructor.
Definition: qrcode.php:639
allocate($setLength)
Return an array with zeros.
Definition: qrcode.php:2129
makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false)
makeMaskNo
Definition: qrcode.php:1088
$rsblocks
Reed-Solomon blocks.
Definition: qrcode.php:397
$dataLength
Data length.
Definition: qrcode.php:409
mask7($x, $y)
mask7
Definition: qrcode.php:1053
rsEccCodes2($spec)
Return ecc codes 2.
Definition: qrcode.php:2667
encodeModeStructure($inputitem)
encodeModeStructure
Definition: qrcode.php:1626
eatKanji()
eatKanji
Definition: qrcode.php:1383
convertData($items)
convertData
Definition: qrcode.php:2026
encodeMask($mask)
Encode mask.
Definition: qrcode.php:720
$count
Counter.
Definition: qrcode.php:403
splitString()
splitString
Definition: qrcode.php:1445
$blocks
Blocks.
Definition: qrcode.php:391
estimateBitsModeNum($size)
estimateBitsModeNum
Definition: qrcode.php:1786
mask4($x, $y)
mask4
Definition: qrcode.php:1023
$dataStr
Input data string.
Definition: qrcode.php:437
$items
Input items.
Definition: qrcode.php:443
rsEccLength($spec)
Return ecc length.
Definition: qrcode.php:2685
$formatInfo
Array Format information.
Definition: qrcode.php:619
mask5($x, $y)
mask5
Definition: qrcode.php:1033
eatAn()
eatAn
Definition: qrcode.php:1344
$version
QR code version.
Definition: qrcode.php:303
createFrame($version)
Return a copy of initialized frame.
Definition: qrcode.php:2530
binarize($frame)
Convert the frame in binary form.
Definition: qrcode.php:689
putAlignmentPattern($version, $frame, $width)
Put an alignment pattern.
Definition: qrcode.php:2439
mask($width, $frame, $level)
mask
Definition: qrcode.php:1220
$data
Mask data.
Definition: qrcode.php:333
estimateBitStreamSize($items, $version)
estimateBitStreamSize
Definition: qrcode.php:1892
getMinimumVersion($size, $level)
Return a version number that satisfies the input code length.
Definition: qrcode.php:2322
encodeModeAn($inputitem, $version)
encodeModeAn
Definition: qrcode.php:1564
$y
Y position of bit.
Definition: qrcode.php:359
getVersionPattern($version)
Return BCH encoded version information pattern that is used for the symbol of version 7 or greater.
Definition: qrcode.php:2479
encodeMode8($inputitem, $version)
encodeMode8
Definition: qrcode.php:1587
rsEccCodes1($spec)
Return ecc codes 1.
Definition: qrcode.php:2640
mergeBitStream($items)
mergeBitStream
Definition: qrcode.php:2088
encodeModeNum($inputitem, $version)
encodeModeNum
Definition: qrcode.php:1535
getECCLength($version, $level)
Return maximum error correction code length (bytes) for the version.
Definition: qrcode.php:2294
newInputItem($mode, $size, $data, $bstream=null)
newInputItem
Definition: qrcode.php:1513
lengthIndicator($mode, $version)
Return the size of length indicator for the mode and version.
Definition: qrcode.php:2339
appendNewInputItem($items, $mode, $size, $data)
Append data to an input object.
Definition: qrcode.php:1696
$width
Width.
Definition: qrcode.php:341
$lengthTableBits
Array Length indicator.
Definition: qrcode.php:527
$casesensitive
Boolean flag, if true the input string will be converted to uppercase.
Definition: qrcode.php:321
insertStructuredAppendHeader($items, $size, $index, $parity)
insertStructuredAppendHeader
Definition: qrcode.php:1712
mask0($x, $y)
mask0
Definition: qrcode.php:983
evaluateSymbol($width, $frame)
evaluateSymbol
Definition: qrcode.php:1158
getNextPosition()
Return the next frame position.
Definition: qrcode.php:803
$ecccode
Error correction code.
Definition: qrcode.php:385
isdigitat($str, $pos)
Return true if the character at specified position is a number.
Definition: qrcode.php:1262
check($mode, $size, $data)
Validate the input data.
Definition: qrcode.php:1859
calcParity($items)
calcParity
Definition: qrcode.php:1730
getCode()
Return Reed-Solomon block code.
Definition: qrcode.php:910
modnn($rs, $x)
modnn
Definition: qrcode.php:2726
newFromBytes($size, $data)
Return new bitstream from bytes.
Definition: qrcode.php:2159
$bit
Single bit value.
Definition: qrcode.php:371
eat8()
eat8
Definition: qrcode.php:1396
eatNum()
eatNum
Definition: qrcode.php:1312
mask1($x, $y)
mask1
Definition: qrcode.php:993
checkModeNum($size, $data)
checkModeNum
Definition: qrcode.php:1748
encodeBitStream($inputitem, $version)
encodeBitStream
Definition: qrcode.php:1641
newFrame($version)
Set new frame for the specified version.
Definition: qrcode.php:2595
$structured
Structured QR code (not supported yet).
Definition: qrcode.php:327
rsDataCodes2($spec)
Return data codes 2.
Definition: qrcode.php:2658
mask6($x, $y)
mask6
Definition: qrcode.php:1043
encodeModeKanji($inputitem, $version)
encodeModeKanji
Definition: qrcode.php:1603
estimateBitsModeKanji($size)
estimateBitsModeKanji
Definition: qrcode.php:1829
getFrameAt($at)
Get frame value at specified position.
Definition: qrcode.php:795
writeFormatInformation($width, &$frame, $mask, $level)
Write Format Information on frame and returns the number of black bits.
Definition: qrcode.php:941
init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
Initialize a Reed-Solomon codec and add it to existing rsitems.
Definition: qrcode.php:2703
getWidth($version)
Return the width of the symbol for the version.
Definition: qrcode.php:2303
appendBitstream($bitstream, $append)
Append one bitstream to another.
Definition: qrcode.php:2183
qrstrset($srctab, $x, $y, $repl, $replLen=false)
Replace a value on the array at the specified position.
Definition: qrcode.php:2273
getRemainder($version)
Return the numer of remainder bits.
Definition: qrcode.php:2312
rsDataCodes1($spec)
Return data codes 1.
Definition: qrcode.php:2631
rsDataLength($spec)
Return data length.
Definition: qrcode.php:2676
appendPaddingBit($bstream)
Append Padding Bit to bitstream.
Definition: qrcode.php:2055
rsBlockNum1($spec)
Return block number 1.
Definition: qrcode.php:2622
$barcode_array
Barcode array to be returned which is readable by TCPDF.
Definition: qrcode.php:297
$versionPattern
Array Version information pattern (BCH coded).
Definition: qrcode.php:607
makeMask($width, $frame, $maskNo, $level)
makeMask
Definition: qrcode.php:1115
generateMaskNo($maskNo, $width, $frame)
Return bitmask.
Definition: qrcode.php:1064
toUpper()
toUpper
Definition: qrcode.php:1484
createBitStream($items)
createBitStream
Definition: qrcode.php:2011
init($spec)
Initialize code.
Definition: qrcode.php:859
mask2($x, $y)
mask2
Definition: qrcode.php:1003
appendNum($bitstream, $bits, $num)
Append one bitstream created from number to another.
Definition: qrcode.php:2200
checkModeKanji($size, $data)
checkModeKanji
Definition: qrcode.php:1839
getBitStream($items)
Returns a stream of bits.
Definition: qrcode.php:2105
getBarcodeArray()
Returns a barcode array which is readable by TCPDF.
Definition: qrcode.php:680
init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
Initialize a Reed-Solomon codec and returns an array of values.
Definition: qrcode.php:2744
$hint
Encoding mode.
Definition: qrcode.php:315
encodeString($string)
Encode the input string to QR code.
Definition: qrcode.php:704
$dir
Direction.
Definition: qrcode.php:365
newFromNum($bits, $num)
Return new bitstream from number.
Definition: qrcode.php:2139
$h
$w
$mask
Definition: example_042.php:90
$code
Definition: example_050.php:99