Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/tcpdf/qrcode.php
Go to the documentation of this file.
00001 <?php
00002 //============================================================+
00003 // File name   : qrcode.php
00004 // Version     : 1.0.009
00005 // Begin       : 2010-03-22
00006 // Last Update : 2010-12-16
00007 // Author      : Nicola Asuni - Tecnick.com S.r.l - Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
00008 // License     : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
00009 // -------------------------------------------------------------------
00010 // Copyright (C) 2010-2010  Nicola Asuni - Tecnick.com S.r.l.
00011 //
00012 // This file is part of TCPDF software library.
00013 //
00014 // TCPDF is free software: you can redistribute it and/or modify it
00015 // under the terms of the GNU Lesser General Public License as
00016 // published by the Free Software Foundation, either version 3 of the
00017 // License, or (at your option) any later version.
00018 //
00019 // TCPDF is distributed in the hope that it will be useful, but
00020 // WITHOUT ANY WARRANTY; without even the implied warranty of
00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 // See the GNU Lesser General Public License for more details.
00023 //
00024 // You should have received a copy of the GNU Lesser General Public License
00025 // along with TCPDF.  If not, see <http://www.gnu.org/licenses/>.
00026 //
00027 // See LICENSE.TXT file for more information.
00028 // -------------------------------------------------------------------
00029 //
00030 // DESCRIPTION :
00031 //
00032 // Class to create QR-code arrays for TCPDF class.
00033 // QR Code symbol is a 2D barcode that can be scanned by
00034 // handy terminals such as a mobile phone with CCD.
00035 // The capacity of QR Code is up to 7000 digits or 4000
00036 // characters, and has high robustness.
00037 // This class supports QR Code model 2, described in
00038 // JIS (Japanese Industrial Standards) X0510:2004
00039 // or ISO/IEC 18004.
00040 // Currently the following features are not supported:
00041 // ECI and FNC1 mode, Micro QR Code, QR Code model 1,
00042 // Structured mode.
00043 //
00044 // This class is derived from the following projects:
00045 // ---------------------------------------------------------
00046 // "PHP QR Code encoder"
00047 // License: GNU-LGPLv3
00048 // Copyright (C) 2010 by Dominik Dzienia <deltalab at poczta dot fm>
00049 // http://phpqrcode.sourceforge.net/
00050 // https://sourceforge.net/projects/phpqrcode/
00051 //
00052 // The "PHP QR Code encoder" is based on
00053 // "C libqrencode library" (ver. 3.1.1)
00054 // License: GNU-LGPL 2.1
00055 // Copyright (C) 2006-2010 by Kentaro Fukuchi
00056 // http://megaui.net/fukuchi/works/qrencode/index.en.html
00057 //
00058 // Reed-Solomon code encoder is written by Phil Karn, KA9Q.
00059 // Copyright (C) 2002-2006 Phil Karn, KA9Q
00060 //
00061 // QR Code is registered trademark of DENSO WAVE INCORPORATED
00062 // http://www.denso-wave.com/qrcode/index-e.html
00063 // ---------------------------------------------------------
00064 //============================================================+
00065 
00082 // definitions
00083 if (!defined('QRCODEDEFS')) {
00084 
00088         define('QRCODEDEFS', true);
00089 
00090         // -----------------------------------------------------
00091 
00092         // Encoding modes (characters which can be encoded in QRcode)
00093 
00097         define('QR_MODE_NL', -1);
00098 
00102         define('QR_MODE_NM', 0);
00103 
00107         define('QR_MODE_AN', 1);
00108 
00112         define('QR_MODE_8B', 2);
00113 
00117         define('QR_MODE_KJ', 3);
00118 
00122         define('QR_MODE_ST', 4);
00123 
00124         // -----------------------------------------------------
00125 
00126         // Levels of error correction.
00127         // QRcode has a function of an error correcting for miss reading that white is black.
00128         // Error correcting is defined in 4 level as below.
00129 
00133         define('QR_ECLEVEL_L', 0);
00134 
00138         define('QR_ECLEVEL_M', 1);
00139 
00143         define('QR_ECLEVEL_Q', 2);
00144 
00148         define('QR_ECLEVEL_H', 3);
00149 
00150         // -----------------------------------------------------
00151 
00152         // Version. Size of QRcode is defined as version.
00153         // Version is from 1 to 40.
00154         // Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
00155         // So version 40 is 177*177 matrix.
00156 
00160         define('QRSPEC_VERSION_MAX', 40);
00161 
00165     define('QRSPEC_WIDTH_MAX', 177);
00166 
00167         // -----------------------------------------------------
00168 
00172     define('QRCAP_WIDTH',    0);
00173 
00177     define('QRCAP_WORDS',    1);
00178 
00182     define('QRCAP_REMINDER', 2);
00183 
00187     define('QRCAP_EC',       3);
00188 
00189         // -----------------------------------------------------
00190 
00191         // Structure (currently usupported)
00192 
00196     define('STRUCTURE_HEADER_BITS',  20);
00197 
00201     define('MAX_STRUCTURED_SYMBOLS', 16);
00202 
00203         // -----------------------------------------------------
00204 
00205     // Masks
00206 
00210     define('N1',  3);
00211 
00215         define('N2',  3);
00216 
00220         define('N3', 40);
00221 
00225         define('N4', 10);
00226 
00227         // -----------------------------------------------------
00228 
00229         // Optimization settings
00230 
00234         define('QR_FIND_BEST_MASK', true);
00235 
00239         define('QR_FIND_FROM_RANDOM', 2);
00240 
00244         define('QR_DEFAULT_MASK', 2);
00245 
00246         // -----------------------------------------------------
00247 
00248 } // end of definitions
00249 
00250 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
00251 
00252 // for compatibility with PHP4
00253 if (!function_exists('str_split')) {
00260         function str_split($string, $split_length=1) {
00261                 if ((strlen($string) > $split_length) OR (!$split_length)) {
00262                         do {
00263                                 $c = strlen($string);
00264                                 $parts[] = substr($string, 0, $split_length);
00265                                 $string = substr($string, $split_length);
00266                         } while ($string !== false);
00267                 } else {
00268                         $parts = array($string);
00269                 }
00270                 return $parts;
00271         }
00272 }
00273 
00274 // #####################################################
00275 
00291 class QRcode {
00292 
00297         protected $barcode_array = array();
00298 
00303         protected $version = 0;
00304 
00309         protected $level = QR_ECLEVEL_L;
00310 
00315         protected $hint = QR_MODE_8B;
00316 
00321         protected $casesensitive = true;
00322 
00327         protected $structured = 0;
00328 
00333         protected $data;
00334 
00335         // FrameFiller
00336 
00341         protected $width;
00342 
00347         protected $frame;
00348 
00353         protected $x;
00354 
00359         protected $y;
00360 
00365         protected $dir;
00366 
00371         protected $bit;
00372 
00373         // ---- QRrawcode ----
00374 
00379         protected $datacode = array();
00380 
00385         protected $ecccode = array();
00386 
00391         protected $blocks;
00392 
00397         protected $rsblocks = array(); //of RSblock
00398 
00403         protected $count;
00404 
00409         protected $dataLength;
00410 
00415         protected $eccLength;
00416 
00421         protected $b1;
00422 
00423         // ---- QRmask ----
00424 
00429         protected $runLength = array();
00430 
00431         // ---- QRsplit ----
00432 
00437         protected $dataStr = '';
00438 
00443         protected $items;
00444 
00445         // Reed-Solomon items
00446 
00451         protected $rsitems = array();
00452 
00457         protected $frames = array();
00458 
00463         protected $anTable = array(
00464                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
00465                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
00466                 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
00467                  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1, //
00468                 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
00469                 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
00470                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
00471                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  //
00472                 );
00473 
00479         protected $capacity = array(
00480                 array(  0,    0, 0, array(   0,    0,    0,    0)), //
00481                 array( 21,   26, 0, array(   7,   10,   13,   17)), //  1
00482                 array( 25,   44, 7, array(  10,   16,   22,   28)), //
00483                 array( 29,   70, 7, array(  15,   26,   36,   44)), //
00484                 array( 33,  100, 7, array(  20,   36,   52,   64)), //
00485                 array( 37,  134, 7, array(  26,   48,   72,   88)), //  5
00486                 array( 41,  172, 7, array(  36,   64,   96,  112)), //
00487                 array( 45,  196, 0, array(  40,   72,  108,  130)), //
00488                 array( 49,  242, 0, array(  48,   88,  132,  156)), //
00489                 array( 53,  292, 0, array(  60,  110,  160,  192)), //
00490                 array( 57,  346, 0, array(  72,  130,  192,  224)), // 10
00491                 array( 61,  404, 0, array(  80,  150,  224,  264)), //
00492                 array( 65,  466, 0, array(  96,  176,  260,  308)), //
00493                 array( 69,  532, 0, array( 104,  198,  288,  352)), //
00494                 array( 73,  581, 3, array( 120,  216,  320,  384)), //
00495                 array( 77,  655, 3, array( 132,  240,  360,  432)), // 15
00496                 array( 81,  733, 3, array( 144,  280,  408,  480)), //
00497                 array( 85,  815, 3, array( 168,  308,  448,  532)), //
00498                 array( 89,  901, 3, array( 180,  338,  504,  588)), //
00499                 array( 93,  991, 3, array( 196,  364,  546,  650)), //
00500                 array( 97, 1085, 3, array( 224,  416,  600,  700)), // 20
00501                 array(101, 1156, 4, array( 224,  442,  644,  750)), //
00502                 array(105, 1258, 4, array( 252,  476,  690,  816)), //
00503                 array(109, 1364, 4, array( 270,  504,  750,  900)), //
00504                 array(113, 1474, 4, array( 300,  560,  810,  960)), //
00505                 array(117, 1588, 4, array( 312,  588,  870, 1050)), // 25
00506                 array(121, 1706, 4, array( 336,  644,  952, 1110)), //
00507                 array(125, 1828, 4, array( 360,  700, 1020, 1200)), //
00508                 array(129, 1921, 3, array( 390,  728, 1050, 1260)), //
00509                 array(133, 2051, 3, array( 420,  784, 1140, 1350)), //
00510                 array(137, 2185, 3, array( 450,  812, 1200, 1440)), // 30
00511                 array(141, 2323, 3, array( 480,  868, 1290, 1530)), //
00512                 array(145, 2465, 3, array( 510,  924, 1350, 1620)), //
00513                 array(149, 2611, 3, array( 540,  980, 1440, 1710)), //
00514                 array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
00515                 array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
00516                 array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
00517                 array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
00518                 array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
00519                 array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
00520                 array(177, 3706, 0, array( 750, 1372, 2040, 2430))  // 40
00521         );
00522 
00527         protected $lengthTableBits = array(
00528                 array(10, 12, 14),
00529                 array( 9, 11, 13),
00530                 array( 8, 16, 16),
00531                 array( 8, 10, 12)
00532         );
00533 
00539         protected $eccTable = array(
00540                 array(array( 0,  0), array( 0,  0), array( 0,  0), array( 0,  0)), //
00541                 array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //  1
00542                 array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //
00543                 array(array( 1,  0), array( 1,  0), array( 2,  0), array( 2,  0)), //
00544                 array(array( 1,  0), array( 2,  0), array( 2,  0), array( 4,  0)), //
00545                 array(array( 1,  0), array( 2,  0), array( 2,  2), array( 2,  2)), //  5
00546                 array(array( 2,  0), array( 4,  0), array( 4,  0), array( 4,  0)), //
00547                 array(array( 2,  0), array( 4,  0), array( 2,  4), array( 4,  1)), //
00548                 array(array( 2,  0), array( 2,  2), array( 4,  2), array( 4,  2)), //
00549                 array(array( 2,  0), array( 3,  2), array( 4,  4), array( 4,  4)), //
00550                 array(array( 2,  2), array( 4,  1), array( 6,  2), array( 6,  2)), // 10
00551                 array(array( 4,  0), array( 1,  4), array( 4,  4), array( 3,  8)), //
00552                 array(array( 2,  2), array( 6,  2), array( 4,  6), array( 7,  4)), //
00553                 array(array( 4,  0), array( 8,  1), array( 8,  4), array(12,  4)), //
00554                 array(array( 3,  1), array( 4,  5), array(11,  5), array(11,  5)), //
00555                 array(array( 5,  1), array( 5,  5), array( 5,  7), array(11,  7)), // 15
00556                 array(array( 5,  1), array( 7,  3), array(15,  2), array( 3, 13)), //
00557                 array(array( 1,  5), array(10,  1), array( 1, 15), array( 2, 17)), //
00558                 array(array( 5,  1), array( 9,  4), array(17,  1), array( 2, 19)), //
00559                 array(array( 3,  4), array( 3, 11), array(17,  4), array( 9, 16)), //
00560                 array(array( 3,  5), array( 3, 13), array(15,  5), array(15, 10)), // 20
00561                 array(array( 4,  4), array(17,  0), array(17,  6), array(19,  6)), //
00562                 array(array( 2,  7), array(17,  0), array( 7, 16), array(34,  0)), //
00563                 array(array( 4,  5), array( 4, 14), array(11, 14), array(16, 14)), //
00564                 array(array( 6,  4), array( 6, 14), array(11, 16), array(30,  2)), //
00565                 array(array( 8,  4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
00566                 array(array(10,  2), array(19,  4), array(28,  6), array(33,  4)), //
00567                 array(array( 8,  4), array(22,  3), array( 8, 26), array(12, 28)), //
00568                 array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
00569                 array(array( 7,  7), array(21,  7), array( 1, 37), array(19, 26)), //
00570                 array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
00571                 array(array(13,  3), array( 2, 29), array(42,  1), array(23, 28)), //
00572                 array(array(17,  0), array(10, 23), array(10, 35), array(19, 35)), //
00573                 array(array(17,  1), array(14, 21), array(29, 19), array(11, 46)), //
00574                 array(array(13,  6), array(14, 23), array(44,  7), array(59,  1)), //
00575                 array(array(12,  7), array(12, 26), array(39, 14), array(22, 41)), // 35
00576                 array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
00577                 array(array(17,  4), array(29, 14), array(49, 10), array(24, 46)), //
00578                 array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
00579                 array(array(20,  4), array(40,  7), array(43, 22), array(10, 67)), //
00580                 array(array(19,  6), array(18, 31), array(34, 34), array(20, 61))  // 40
00581         );
00582 
00589         protected $alignmentPattern = array(
00590                 array( 0,  0),
00591                 array( 0,  0), array(18,  0), array(22,  0), array(26,  0), array(30,  0), //  1- 5
00592                 array(34,  0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), //  6-10
00593                 array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
00594                 array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
00595                 array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
00596                 array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
00597                 array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
00598                 array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58)  // 35-40
00599         );
00600 
00607         protected $versionPattern = array(
00608                 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
00609                 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
00610                 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
00611                 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
00612                 0x27541, 0x28c69
00613         );
00614 
00619         protected $formatInfo = array(
00620                 array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
00621                 array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
00622                 array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
00623                 array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)  //
00624         );
00625 
00626 
00627         // -------------------------------------------------
00628         // -------------------------------------------------
00629 
00630 
00639         public function __construct($code, $eclevel = 'L') {
00640                 $barcode_array = array();
00641                 if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
00642                         return false;
00643                 }
00644                 // set error correction level
00645                 $this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
00646                 if ($this->level === false) {
00647                         $this->level = QR_ECLEVEL_L;
00648                 }
00649                 if (($this->hint != QR_MODE_8B) AND ($this->hint != QR_MODE_KJ)) {
00650                         return false;
00651                 }
00652                 if (($this->version < 0) OR ($this->version > QRSPEC_VERSION_MAX)) {
00653                         return false;
00654                 }
00655                 $this->items = array();
00656                 $this->encodeString($code);
00657                 if (is_null($this->data)) {
00658                         return false;
00659                 }
00660                 $qrTab = $this->binarize($this->data);
00661                 $size = count($qrTab);
00662                 $barcode_array['num_rows'] = $size;
00663                 $barcode_array['num_cols'] = $size;
00664                 $barcode_array['bcode'] = array();
00665                 foreach ($qrTab as $line) {
00666                         $arrAdd = array();
00667                         foreach (str_split($line) as $char) {
00668                                 $arrAdd[] = ($char=='1')?1:0;
00669                         }
00670                         $barcode_array['bcode'][] = $arrAdd;
00671                 }
00672                 $this->barcode_array = $barcode_array;
00673         }
00674 
00680         public function getBarcodeArray() {
00681                 return $this->barcode_array;
00682         }
00683 
00689         protected function binarize($frame) {
00690                 $len = count($frame);
00691                 // the frame is square (width = height)
00692                 foreach ($frame as &$frameLine) {
00693                         for ($i=0; $i<$len; $i++) {
00694                                 $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
00695                         }
00696                 }
00697                 return $frame;
00698         }
00699 
00704         protected function encodeString($string) {
00705                 $this->dataStr = $string;
00706                 if (!$this->casesensitive) {
00707                         $this->toUpper();
00708                 }
00709                 $ret = $this->splitString();
00710                 if ($ret < 0) {
00711                         return NULL;
00712                 }
00713                 $this->encodeMask(-1);
00714         }
00715 
00720         protected function encodeMask($mask) {
00721                 $spec = array(0, 0, 0, 0, 0);
00722                 $this->datacode = $this->getByteStream($this->items);
00723                 if (is_null($this->datacode)) {
00724                         return NULL;
00725                 }
00726                 $spec = $this->getEccSpec($this->version, $this->level, $spec);
00727                 $this->b1 = $this->rsBlockNum1($spec);
00728                 $this->dataLength = $this->rsDataLength($spec);
00729                 $this->eccLength = $this->rsEccLength($spec);
00730                 $this->ecccode = array_fill(0, $this->eccLength, 0);
00731                 $this->blocks = $this->rsBlockNum($spec);
00732                 $ret = $this->init($spec);
00733                 if ($ret < 0) {
00734                         return NULL;
00735                 }
00736                 $this->count = 0;
00737                 $this->width = $this->getWidth($this->version);
00738                 $this->frame = $this->newFrame($this->version);
00739                 $this->x = $this->width - 1;
00740                 $this->y = $this->width - 1;
00741                 $this->dir = -1;
00742                 $this->bit = -1;
00743                 // inteleaved data and ecc codes
00744                 for ($i=0; $i < ($this->dataLength + $this->eccLength); $i++) {
00745                         $code = $this->getCode();
00746                         $bit = 0x80;
00747                         for ($j=0; $j<8; $j++) {
00748                                 $addr = $this->getNextPosition();
00749                                 $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
00750                                 $bit = $bit >> 1;
00751                         }
00752                 }
00753                 // remainder bits
00754                 $j = $this->getRemainder($this->version);
00755                 for ($i=0; $i<$j; $i++) {
00756                         $addr = $this->getNextPosition();
00757                         $this->setFrameAt($addr, 0x02);
00758                 }
00759                 // masking
00760                 $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
00761                 if ($mask < 0) {
00762                         if (QR_FIND_BEST_MASK) {
00763                                 $masked = $this->mask($this->width, $this->frame, $this->level);
00764                         } else {
00765                                 $masked = $this->makeMask($this->width, $this->frame, (intval(QR_DEFAULT_MASK) % 8), $this->level);
00766                         }
00767                 } else {
00768                         $masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
00769                 }
00770                 if ($masked == NULL) {
00771                         return NULL;
00772                 }
00773                 $this->data = $masked;
00774         }
00775 
00776         // - - - - - - - - - - - - - - - - - - - - - - - - -
00777 
00778         // FrameFiller
00779 
00785         protected function setFrameAt($at, $val) {
00786                 $this->frame[$at['y']][$at['x']] = chr($val);
00787         }
00788 
00794         protected function getFrameAt($at) {
00795                 return ord($this->frame[$at['y']][$at['x']]);
00796         }
00797 
00802         protected function getNextPosition() {
00803                 do {
00804                         if ($this->bit == -1) {
00805                                 $this->bit = 0;
00806                                 return array('x'=>$this->x, 'y'=>$this->y);
00807                         }
00808                         $x = $this->x;
00809                         $y = $this->y;
00810                         $w = $this->width;
00811                         if ($this->bit == 0) {
00812                                 $x--;
00813                                 $this->bit++;
00814                         } else {
00815                                 $x++;
00816                                 $y += $this->dir;
00817                                 $this->bit--;
00818                         }
00819                         if ($this->dir < 0) {
00820                                 if ($y < 0) {
00821                                         $y = 0;
00822                                         $x -= 2;
00823                                         $this->dir = 1;
00824                                         if ($x == 6) {
00825                                                 $x--;
00826                                                 $y = 9;
00827                                         }
00828                                 }
00829                         } else {
00830                                 if ($y == $w) {
00831                                         $y = $w - 1;
00832                                         $x -= 2;
00833                                         $this->dir = -1;
00834                                         if ($x == 6) {
00835                                                 $x--;
00836                                                 $y -= 8;
00837                                         }
00838                                 }
00839                         }
00840                         if (($x < 0) OR ($y < 0)) {
00841                                 return NULL;
00842                         }
00843                         $this->x = $x;
00844                         $this->y = $y;
00845                 } while(ord($this->frame[$y][$x]) & 0x80);
00846                 return array('x'=>$x, 'y'=>$y);
00847         }
00848 
00849         // - - - - - - - - - - - - - - - - - - - - - - - - -
00850 
00851         // QRrawcode
00852 
00858         protected function init($spec) {
00859                 $dl = $this->rsDataCodes1($spec);
00860                 $el = $this->rsEccCodes1($spec);
00861                 $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
00862                 $blockNo = 0;
00863                 $dataPos = 0;
00864                 $eccPos = 0;
00865                 $endfor = $this->rsBlockNum1($spec);
00866                 for ($i=0; $i < $endfor; ++$i) {
00867                         $ecc = array_slice($this->ecccode, $eccPos);
00868                         $this->rsblocks[$blockNo] = array();
00869                         $this->rsblocks[$blockNo]['dataLength'] = $dl;
00870                         $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
00871                         $this->rsblocks[$blockNo]['eccLength'] = $el;
00872                         $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
00873                         $this->rsblocks[$blockNo]['ecc'] = $ecc;
00874                         $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
00875                         $dataPos += $dl;
00876                         $eccPos += $el;
00877                         $blockNo++;
00878                 }
00879                 if ($this->rsBlockNum2($spec) == 0) {
00880                         return 0;
00881                 }
00882                 $dl = $this->rsDataCodes2($spec);
00883                 $el = $this->rsEccCodes2($spec);
00884                 $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
00885                 if ($rs == NULL) {
00886                         return -1;
00887                 }
00888                 $endfor = $this->rsBlockNum2($spec);
00889                 for ($i=0; $i < $endfor; ++$i) {
00890                         $ecc = array_slice($this->ecccode, $eccPos);
00891                         $this->rsblocks[$blockNo] = array();
00892                         $this->rsblocks[$blockNo]['dataLength'] = $dl;
00893                         $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
00894                         $this->rsblocks[$blockNo]['eccLength'] = $el;
00895                         $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
00896                         $this->rsblocks[$blockNo]['ecc'] = $ecc;
00897                         $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
00898                         $dataPos += $dl;
00899                         $eccPos += $el;
00900                         $blockNo++;
00901                 }
00902                 return 0;
00903         }
00904 
00909         protected function getCode() {
00910                 if ($this->count < $this->dataLength) {
00911                         $row = $this->count % $this->blocks;
00912                         $col = $this->count / $this->blocks;
00913                         if ($col >= $this->rsblocks[0]['dataLength']) {
00914                                 $row += $this->b1;
00915                         }
00916                         $ret = $this->rsblocks[$row]['data'][$col];
00917                 } elseif ($this->count < $this->dataLength + $this->eccLength) {
00918                         $row = ($this->count - $this->dataLength) % $this->blocks;
00919                         $col = ($this->count - $this->dataLength) / $this->blocks;
00920                         $ret = $this->rsblocks[$row]['ecc'][$col];
00921                 } else {
00922                         return 0;
00923                 }
00924                 $this->count++;
00925                 return $ret;
00926         }
00927 
00928         // - - - - - - - - - - - - - - - - - - - - - - - - -
00929 
00930         // QRmask
00931 
00940          protected function writeFormatInformation($width, &$frame, $mask, $level) {
00941                 $blacks = 0;
00942                 $format =  $this->getFormatInfo($mask, $level);
00943                 for ($i=0; $i<8; ++$i) {
00944                         if ($format & 1) {
00945                                 $blacks += 2;
00946                                 $v = 0x85;
00947                         } else {
00948                                 $v = 0x84;
00949                         }
00950                         $frame[8][$width - 1 - $i] = chr($v);
00951                         if ($i < 6) {
00952                                 $frame[$i][8] = chr($v);
00953                         } else {
00954                                 $frame[$i + 1][8] = chr($v);
00955                         }
00956                         $format = $format >> 1;
00957                 }
00958                 for ($i=0; $i<7; ++$i) {
00959                 if ($format & 1) {
00960                         $blacks += 2;
00961                         $v = 0x85;
00962                 } else {
00963                         $v = 0x84;
00964                 }
00965                 $frame[$width - 7 + $i][8] = chr($v);
00966                 if ($i == 0) {
00967                         $frame[8][7] = chr($v);
00968                 } else {
00969                         $frame[8][6 - $i] = chr($v);
00970                 }
00971                 $format = $format >> 1;
00972                 }
00973                 return $blacks;
00974         }
00975 
00982          protected function mask0($x, $y) {
00983                 return ($x + $y) & 1;
00984         }
00985 
00992          protected function mask1($x, $y) {
00993                 return ($y & 1);
00994         }
00995 
01002          protected function mask2($x, $y) {
01003                 return ($x % 3);
01004         }
01005 
01012          protected function mask3($x, $y) {
01013                 return ($x + $y) % 3;
01014         }
01015 
01022          protected function mask4($x, $y) {
01023                 return (((int)($y / 2)) + ((int)($x / 3))) & 1;
01024         }
01025 
01032          protected function mask5($x, $y) {
01033                 return (($x * $y) & 1) + ($x * $y) % 3;
01034         }
01035 
01042          protected function mask6($x, $y) {
01043                 return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
01044         }
01045 
01052          protected function mask7($x, $y) {
01053                 return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
01054         }
01055 
01063         protected function generateMaskNo($maskNo, $width, $frame) {
01064                 $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
01065                 for ($y=0; $y<$width; ++$y) {
01066                         for ($x=0; $x<$width; ++$x) {
01067                                 if (ord($frame[$y][$x]) & 0x80) {
01068                                         $bitMask[$y][$x] = 0;
01069                                 } else {
01070                                         $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
01071                                         $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
01072                                 }
01073                         }
01074                 }
01075                 return $bitMask;
01076         }
01077 
01087          protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
01088                 $b = 0;
01089                 $bitMask = array();
01090                 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
01091                 if ($maskGenOnly) {
01092                         return;
01093                 }
01094                 $d = $s;
01095                 for ($y=0; $y<$width; ++$y) {
01096                         for ($x=0; $x<$width; ++$x) {
01097                                 if ($bitMask[$y][$x] == 1) {
01098                                         $d[$y][$x] = chr(ord($s[$y][$x]) ^ ((int)($bitMask[$y][$x])));
01099                                 }
01100                                 $b += (int)(ord($d[$y][$x]) & 1);
01101                         }
01102                 }
01103                 return $b;
01104         }
01105 
01114          protected function makeMask($width, $frame, $maskNo, $level) {
01115                 $masked = array_fill(0, $width, str_repeat("\0", $width));
01116                 $this->makeMaskNo($maskNo, $width, $frame, $masked);
01117                 $this->writeFormatInformation($width, $masked, $maskNo, $level);
01118                 return $masked;
01119         }
01120 
01126          protected function calcN1N3($length) {
01127                 $demerit = 0;
01128                 for ($i=0; $i<$length; ++$i) {
01129                         if ($this->runLength[$i] >= 5) {
01130                                 $demerit += (N1 + ($this->runLength[$i] - 5));
01131                         }
01132                         if ($i & 1) {
01133                                 if (($i >= 3) AND ($i < ($length-2)) AND ($this->runLength[$i] % 3 == 0)) {
01134                                         $fact = (int)($this->runLength[$i] / 3);
01135                                         if (($this->runLength[$i-2] == $fact)
01136                                                 AND ($this->runLength[$i-1] == $fact)
01137                                                 AND ($this->runLength[$i+1] == $fact)
01138                                                 AND ($this->runLength[$i+2] == $fact)) {
01139                                                 if (($this->runLength[$i-3] < 0) OR ($this->runLength[$i-3] >= (4 * $fact))) {
01140                                                         $demerit += N3;
01141                                                 } elseif ((($i+3) >= $length) OR ($this->runLength[$i+3] >= (4 * $fact))) {
01142                                                         $demerit += N3;
01143                                                 }
01144                                         }
01145                                 }
01146                         }
01147                 }
01148                 return $demerit;
01149         }
01150 
01157          protected function evaluateSymbol($width, $frame) {
01158                 $head = 0;
01159                 $demerit = 0;
01160                 for ($y=0; $y<$width; ++$y) {
01161                         $head = 0;
01162                         $this->runLength[0] = 1;
01163                         $frameY = $frame[$y];
01164                         if ($y > 0) {
01165                                 $frameYM = $frame[$y-1];
01166                         }
01167                         for ($x=0; $x<$width; ++$x) {
01168                                 if (($x > 0) AND ($y > 0)) {
01169                                         $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
01170                                         $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
01171                                         if (($b22 | ($w22 ^ 1)) & 1) {
01172                                                 $demerit += N2;
01173                                         }
01174                                 }
01175                                 if (($x == 0) AND (ord($frameY[$x]) & 1)) {
01176                                         $this->runLength[0] = -1;
01177                                         $head = 1;
01178                                         $this->runLength[$head] = 1;
01179                                 } elseif ($x > 0) {
01180                                         if ((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
01181                                                 $head++;
01182                                                 $this->runLength[$head] = 1;
01183                                         } else {
01184                                                 $this->runLength[$head]++;
01185                                         }
01186                                 }
01187                         }
01188                         $demerit += $this->calcN1N3($head+1);
01189                 }
01190                 for ($x=0; $x<$width; ++$x) {
01191                         $head = 0;
01192                         $this->runLength[0] = 1;
01193                         for ($y=0; $y<$width; ++$y) {
01194                                 if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
01195                                         $this->runLength[0] = -1;
01196                                         $head = 1;
01197                                         $this->runLength[$head] = 1;
01198                                 } elseif ($y > 0) {
01199                                         if ((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
01200                                                 $head++;
01201                                                 $this->runLength[$head] = 1;
01202                                         } else {
01203                                                 $this->runLength[$head]++;
01204                                         }
01205                                 }
01206                         }
01207                         $demerit += $this->calcN1N3($head+1);
01208                 }
01209                 return $demerit;
01210         }
01211 
01219          protected function mask($width, $frame, $level) {
01220                 $minDemerit = PHP_INT_MAX;
01221                 $bestMaskNum = 0;
01222                 $bestMask = array();
01223                 $checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
01224                 if (QR_FIND_FROM_RANDOM !== false) {
01225                         $howManuOut = 8 - (QR_FIND_FROM_RANDOM % 9);
01226                         for ($i = 0; $i <  $howManuOut; ++$i) {
01227                                 $remPos = rand (0, count($checked_masks)-1);
01228                                 unset($checked_masks[$remPos]);
01229                                 $checked_masks = array_values($checked_masks);
01230                         }
01231                 }
01232                 $bestMask = $frame;
01233                 foreach ($checked_masks as $i) {
01234                         $mask = array_fill(0, $width, str_repeat("\0", $width));
01235                         $demerit = 0;
01236                         $blacks = 0;
01237                         $blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
01238                         $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
01239                         $blacks  = (int)(100 * $blacks / ($width * $width));
01240                         $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
01241                         $demerit += $this->evaluateSymbol($width, $mask);
01242                         if ($demerit < $minDemerit) {
01243                                 $minDemerit = $demerit;
01244                                 $bestMask = $mask;
01245                                 $bestMaskNum = $i;
01246                         }
01247                 }
01248                 return $bestMask;
01249         }
01250 
01251         // - - - - - - - - - - - - - - - - - - - - - - - - -
01252 
01253         // QRsplit
01254 
01261          protected function isdigitat($str, $pos) {
01262                 if ($pos >= strlen($str)) {
01263                         return false;
01264                 }
01265                 return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
01266         }
01267 
01274          protected function isalnumat($str, $pos) {
01275                 if ($pos >= strlen($str)) {
01276                         return false;
01277                 }
01278                 return ($this->lookAnTable(ord($str[$pos])) >= 0);
01279         }
01280 
01286          protected function identifyMode($pos) {
01287                 if ($pos >= strlen($this->dataStr)) {
01288                         return QR_MODE_NL;
01289                 }
01290                 $c = $this->dataStr[$pos];
01291                 if ($this->isdigitat($this->dataStr, $pos)) {
01292                         return QR_MODE_NM;
01293                 } elseif ($this->isalnumat($this->dataStr, $pos)) {
01294                         return QR_MODE_AN;
01295                 } elseif ($this->hint == QR_MODE_KJ) {
01296                         if ($pos+1 < strlen($this->dataStr)) {
01297                                 $d = $this->dataStr[$pos+1];
01298                                 $word = (ord($c) << 8) | ord($d);
01299                                 if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
01300                                         return QR_MODE_KJ;
01301                                 }
01302                         }
01303                 }
01304                 return QR_MODE_8B;
01305         }
01306 
01311          protected function eatNum() {
01312                 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
01313                 $p = 0;
01314                 while($this->isdigitat($this->dataStr, $p)) {
01315                         $p++;
01316                 }
01317                 $run = $p;
01318                 $mode = $this->identifyMode($p);
01319                 if ($mode == QR_MODE_8B) {
01320                         $dif = $this->estimateBitsModeNum($run) + 4 + $ln
01321                         + $this->estimateBitsMode8(1)         // + 4 + l8
01322                         - $this->estimateBitsMode8($run + 1); // - 4 - l8
01323                         if ($dif > 0) {
01324                                 return $this->eat8();
01325                         }
01326                 }
01327                 if ($mode == QR_MODE_AN) {
01328                         $dif = $this->estimateBitsModeNum($run) + 4 + $ln
01329                         + $this->estimateBitsModeAn(1)        // + 4 + la
01330                         - $this->estimateBitsModeAn($run + 1);// - 4 - la
01331                         if ($dif > 0) {
01332                                 return $this->eatAn();
01333                         }
01334                 }
01335                 $this->items = $this->appendNewInputItem($this->items, QR_MODE_NM, $run, str_split($this->dataStr));
01336                 return $run;
01337         }
01338 
01343          protected function eatAn() {
01344                 $la = $this->lengthIndicator(QR_MODE_AN,  $this->version);
01345                 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
01346                 $p =1 ;
01347                 while($this->isalnumat($this->dataStr, $p)) {
01348                         if ($this->isdigitat($this->dataStr, $p)) {
01349                                 $q = $p;
01350                                 while($this->isdigitat($this->dataStr, $q)) {
01351                                         $q++;
01352                                 }
01353                                 $dif = $this->estimateBitsModeAn($p) // + 4 + la
01354                                 + $this->estimateBitsModeNum($q - $p) + 4 + $ln
01355                                 - $this->estimateBitsModeAn($q); // - 4 - la
01356                                 if ($dif < 0) {
01357                                         break;
01358                                 } else {
01359                                         $p = $q;
01360                                 }
01361                         } else {
01362                                 $p++;
01363                         }
01364                 }
01365                 $run = $p;
01366                 if (!$this->isalnumat($this->dataStr, $p)) {
01367                         $dif = $this->estimateBitsModeAn($run) + 4 + $la
01368                         + $this->estimateBitsMode8(1) // + 4 + l8
01369                         - $this->estimateBitsMode8($run + 1); // - 4 - l8
01370                         if ($dif > 0) {
01371                                 return $this->eat8();
01372                         }
01373                 }
01374                 $this->items = $this->appendNewInputItem($this->items, QR_MODE_AN, $run, str_split($this->dataStr));
01375                 return $run;
01376         }
01377 
01382          protected function eatKanji() {
01383                 $p = 0;
01384                 while($this->identifyMode($p) == QR_MODE_KJ) {
01385                         $p += 2;
01386                 }
01387                 $this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr));
01388                 return $run;
01389         }
01390 
01395          protected function eat8() {
01396                 $la = $this->lengthIndicator(QR_MODE_AN, $this->version);
01397                 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
01398                 $p = 1;
01399                 $dataStrLen = strlen($this->dataStr);
01400                 while($p < $dataStrLen) {
01401                         $mode = $this->identifyMode($p);
01402                         if ($mode == QR_MODE_KJ) {
01403                                 break;
01404                         }
01405                         if ($mode == QR_MODE_NM) {
01406                                 $q = $p;
01407                                 while($this->isdigitat($this->dataStr, $q)) {
01408                                         $q++;
01409                                 }
01410                                 $dif = $this->estimateBitsMode8($p) // + 4 + l8
01411                                 + $this->estimateBitsModeNum($q - $p) + 4 + $ln
01412                                 - $this->estimateBitsMode8($q); // - 4 - l8
01413                                 if ($dif < 0) {
01414                                         break;
01415                                 } else {
01416                                         $p = $q;
01417                                 }
01418                         } elseif ($mode == QR_MODE_AN) {
01419                                 $q = $p;
01420                                 while($this->isalnumat($this->dataStr, $q)) {
01421                                         $q++;
01422                                 }
01423                                 $dif = $this->estimateBitsMode8($p)  // + 4 + l8
01424                                 + $this->estimateBitsModeAn($q - $p) + 4 + $la
01425                                 - $this->estimateBitsMode8($q); // - 4 - l8
01426                                 if ($dif < 0) {
01427                                         break;
01428                                 } else {
01429                                         $p = $q;
01430                                 }
01431                         } else {
01432                                 $p++;
01433                         }
01434                 }
01435                 $run = $p;
01436                 $this->items = $this->appendNewInputItem($this->items, QR_MODE_8B, $run, str_split($this->dataStr));
01437                 return $run;
01438         }
01439 
01443          protected function splitString() {
01444                 while (strlen($this->dataStr) > 0) {
01445                         if ($this->dataStr == '') {
01446                                 return 0;
01447                         }
01448                         $mode = $this->identifyMode(0);
01449                         switch ($mode) {
01450                                 case QR_MODE_NM: {
01451                                         $length = $this->eatNum();
01452                                         break;
01453                                 }
01454                                 case QR_MODE_AN: {
01455                                         $length = $this->eatAn();
01456                                         break;
01457                                 }
01458                                 case QR_MODE_KJ: {
01459                                         if ($hint == QR_MODE_KJ) {
01460                                                 $length = $this->eatKanji();
01461                                         } else {
01462                                                 $length = $this->eat8();
01463                                         }
01464                                         break;
01465                                 }
01466                                 default: {
01467                                         $length = $this->eat8();
01468                                         break;
01469                                 }
01470                         }
01471                         if ($length == 0) {
01472                                 return 0;
01473                         }
01474                         if ($length < 0) {
01475                                 return -1;
01476                         }
01477                         $this->dataStr = substr($this->dataStr, $length);
01478                 }
01479         }
01480 
01484          protected function toUpper() {
01485                 $stringLen = strlen($this->dataStr);
01486                 $p = 0;
01487                 while ($p < $stringLen) {
01488                         $mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
01489                         if ($mode == QR_MODE_KJ) {
01490                                 $p += 2;
01491                         } else {
01492                                 if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
01493                                         $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
01494                                 }
01495                                 $p++;
01496                         }
01497                 }
01498                 return $this->dataStr;
01499         }
01500 
01501         // - - - - - - - - - - - - - - - - - - - - - - - - -
01502 
01503         // QRinputItem
01504 
01513          protected function newInputItem($mode, $size, $data, $bstream=null) {
01514                 $setData = array_slice($data, 0, $size);
01515                 if (count($setData) < $size) {
01516                         $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
01517                 }
01518                 if (!$this->check($mode, $size, $setData)) {
01519                         return NULL;
01520                 }
01521                 $inputitem = array();
01522                 $inputitem['mode'] = $mode;
01523                 $inputitem['size'] = $size;
01524                 $inputitem['data'] = $setData;
01525                 $inputitem['bstream'] = $bstream;
01526                 return $inputitem;
01527         }
01528 
01535          protected function encodeModeNum($inputitem, $version) {
01536                 $words = (int)($inputitem['size'] / 3);
01537                 $inputitem['bstream'] = array();
01538                 $val = 0x1;
01539                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
01540                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_NM, $version), $inputitem['size']);
01541                 for ($i=0; $i < $words; ++$i) {
01542                         $val  = (ord($inputitem['data'][$i*3  ]) - ord('0')) * 100;
01543                         $val += (ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
01544                         $val += (ord($inputitem['data'][$i*3+2]) - ord('0'));
01545                         $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
01546                 }
01547                 if ($inputitem['size'] - $words * 3 == 1) {
01548                         $val = ord($inputitem['data'][$words*3]) - ord('0');
01549                         $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
01550                 } elseif (($inputitem['size'] - ($words * 3)) == 2) {
01551                         $val  = (ord($inputitem['data'][$words*3  ]) - ord('0')) * 10;
01552                         $val += (ord($inputitem['data'][$words*3+1]) - ord('0'));
01553                         $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
01554                 }
01555                 return $inputitem;
01556         }
01557 
01564          protected function encodeModeAn($inputitem, $version) {
01565                 $words = (int)($inputitem['size'] / 2);
01566                 $inputitem['bstream'] = array();
01567                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
01568                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_AN, $version), $inputitem['size']);
01569                 for ($i=0; $i < $words; ++$i) {
01570                         $val  = (int)($this->lookAnTable(ord($inputitem['data'][$i*2])) * 45);
01571                         $val += (int)($this->lookAnTable(ord($inputitem['data'][($i*2)+1])));
01572                         $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
01573                 }
01574                 if ($inputitem['size'] & 1) {
01575                         $val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
01576                         $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
01577                 }
01578                 return $inputitem;
01579         }
01580 
01587          protected function encodeMode8($inputitem, $version) {
01588                 $inputitem['bstream'] = array();
01589                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
01590                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_8B, $version), $inputitem['size']);
01591                 for ($i=0; $i < $inputitem['size']; ++$i) {
01592                         $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
01593                 }
01594                 return $inputitem;
01595         }
01596 
01603          protected function encodeModeKanji($inputitem, $version) {
01604                 $inputitem['bstream'] = array();
01605                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
01606                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
01607                 for ($i=0; $i<$inputitem['size']; $i+=2) {
01608                         $val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
01609                         if ($val <= 0x9ffc) {
01610                                 $val -= 0x8140;
01611                         } else {
01612                                 $val -= 0xc140;
01613                         }
01614                         $h = ($val >> 8) * 0xc0;
01615                         $val = ($val & 0xff) + $h;
01616                         $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
01617                 }
01618                 return $inputitem;
01619         }
01620 
01626          protected function encodeModeStructure($inputitem) {
01627                 $inputitem['bstream'] = array();
01628                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
01629                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
01630                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
01631                 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
01632                 return $inputitem;
01633         }
01634 
01641          protected function encodeBitStream($inputitem, $version) {
01642                 $inputitem['bstream'] = array();
01643                 $words = $this->maximumWords($inputitem['mode'], $version);
01644                 if ($inputitem['size'] > $words) {
01645                         $st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
01646                         $st2 = $this->newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
01647                         $st1 = $this->encodeBitStream($st1, $version);
01648                         $st2 = $this->encodeBitStream($st2, $version);
01649                         $inputitem['bstream'] = array();
01650                         $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
01651                         $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
01652                 } else {
01653                         switch($inputitem['mode']) {
01654                                 case QR_MODE_NM: {
01655                                         $inputitem = $this->encodeModeNum($inputitem, $version);
01656                                         break;
01657                                 }
01658                                 case QR_MODE_AN: {
01659                                         $inputitem = $this->encodeModeAn($inputitem, $version);
01660                                         break;
01661                                 }
01662                                 case QR_MODE_8B: {
01663                                         $inputitem = $this->encodeMode8($inputitem, $version);
01664                                         break;
01665                                 }
01666                                 case QR_MODE_KJ: {
01667                                         $inputitem = $this->encodeModeKanji($inputitem, $version);
01668                                         break;
01669                                 }
01670                                 case QR_MODE_ST: {
01671                                         $inputitem = $this->encodeModeStructure($inputitem);
01672                                         break;
01673                                 }
01674                                 default: {
01675                                         break;
01676                                 }
01677                         }
01678                 }
01679                 return $inputitem;
01680         }
01681 
01682         // - - - - - - - - - - - - - - - - - - - - - - - - -
01683 
01684         // QRinput
01685 
01696         protected function appendNewInputItem($items, $mode, $size, $data) {
01697                 $newitem = $this->newInputItem($mode, $size, $data);
01698                 if (!empty($newitem)) {
01699                         $items[] = $newitem;
01700                 }
01701                 return $items;
01702         }
01703 
01712          protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
01713                 if ($size > MAX_STRUCTURED_SYMBOLS) {
01714                         return -1;
01715                 }
01716                 if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
01717                         return -1;
01718                 }
01719                 $buf = array($size, $index, $parity);
01720                 $entry = $this->newInputItem(QR_MODE_ST, 3, buf);
01721                 array_unshift($items, $entry);
01722                 return $items;
01723         }
01724 
01730          protected function calcParity($items) {
01731                 $parity = 0;
01732                 foreach ($items as $item) {
01733                         if ($item['mode'] != QR_MODE_ST) {
01734                                 for ($i=$item['size']-1; $i>=0; --$i) {
01735                                         $parity ^= $item['data'][$i];
01736                                 }
01737                         }
01738                 }
01739                 return $parity;
01740         }
01741 
01748          protected function checkModeNum($size, $data) {
01749                 for ($i=0; $i<$size; ++$i) {
01750                         if ((ord($data[$i]) < ord('0')) OR (ord($data[$i]) > ord('9'))){
01751                                 return false;
01752                         }
01753                 }
01754                 return true;
01755         }
01756 
01762         protected function lookAnTable($c) {
01763                 return (($c > 127)?-1:$this->anTable[$c]);
01764         }
01765 
01772          protected function checkModeAn($size, $data) {
01773                 for ($i=0; $i<$size; ++$i) {
01774                         if ($this->lookAnTable(ord($data[$i])) == -1) {
01775                                 return false;
01776                         }
01777                 }
01778                 return true;
01779         }
01780 
01786          protected function estimateBitsModeNum($size) {
01787                 $w = (int)($size / 3);
01788                 $bits = ($w * 10);
01789                 switch($size - ($w * 3)) {
01790                         case 1: {
01791                                 $bits += 4;
01792                                 break;
01793                         }
01794                         case 2: {
01795                                 $bits += 7;
01796                                 break;
01797                         }
01798                 }
01799                 return $bits;
01800         }
01801 
01807          protected function estimateBitsModeAn($size) {
01808                 $bits = (int)($size * 5.5); // (size / 2 ) * 11
01809                 if ($size & 1) {
01810                         $bits += 6;
01811                 }
01812                 return $bits;
01813         }
01814 
01820          protected function estimateBitsMode8($size) {
01821                 return (int)($size * 8);
01822         }
01823 
01829          protected function estimateBitsModeKanji($size) {
01830                 return (int)($size * 6.5); // (size / 2 ) * 13
01831         }
01832 
01839          protected function checkModeKanji($size, $data) {
01840                 if ($size & 1) {
01841                         return false;
01842                 }
01843                 for ($i=0; $i<$size; $i+=2) {
01844                         $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
01845                         if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
01846                                 return false;
01847                         }
01848                 }
01849                 return true;
01850         }
01851 
01859         protected function check($mode, $size, $data) {
01860                 if ($size <= 0) {
01861                         return false;
01862                 }
01863                 switch($mode) {
01864                         case QR_MODE_NM: {
01865                                 return $this->checkModeNum($size, $data);
01866                         }
01867                         case QR_MODE_AN: {
01868                                 return $this->checkModeAn($size, $data);
01869                         }
01870                         case QR_MODE_KJ: {
01871                                 return $this->checkModeKanji($size, $data);
01872                         }
01873                         case QR_MODE_8B: {
01874                                 return true;
01875                         }
01876                         case QR_MODE_ST: {
01877                                 return true;
01878                         }
01879                         default: {
01880                                 break;
01881                         }
01882                 }
01883                 return false;
01884         }
01885 
01892          protected function estimateBitStreamSize($items, $version) {
01893                 $bits = 0;
01894                 if ($version == 0) {
01895                         $version = 1;
01896                 }
01897                 foreach ($items as $item) {
01898                         switch($item['mode']) {
01899                                 case QR_MODE_NM: {
01900                                         $bits = $this->estimateBitsModeNum($item['size']);
01901                                         break;
01902                                 }
01903                                 case QR_MODE_AN: {
01904                                         $bits = $this->estimateBitsModeAn($item['size']);
01905                                         break;
01906                                 }
01907                                 case QR_MODE_8B: {
01908                                         $bits = $this->estimateBitsMode8($item['size']);
01909                                         break;
01910                                 }
01911                                 case QR_MODE_KJ: {
01912                                         $bits = $this->estimateBitsModeKanji($item['size']);
01913                                         break;
01914                                 }
01915                                 case QR_MODE_ST: {
01916                                         return STRUCTURE_HEADER_BITS;
01917                                 }
01918                                 default: {
01919                                         return 0;
01920                                 }
01921                         }
01922                         $l = $this->lengthIndicator($item['mode'], $version);
01923                         $m = 1 << $l;
01924                         $num = (int)(($item['size'] + $m - 1) / $m);
01925                         $bits += $num * (4 + $l);
01926                 }
01927                 return $bits;
01928         }
01929 
01935          protected function estimateVersion($items) {
01936                 $version = 0;
01937                 $prev = 0;
01938                 do {
01939                         $prev = $version;
01940                         $bits = $this->estimateBitStreamSize($items, $prev);
01941                         $version = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
01942                         if ($version < 0) {
01943                                 return -1;
01944                         }
01945                 } while ($version > $prev);
01946                 return $version;
01947         }
01948 
01956          protected function lengthOfCode($mode, $version, $bits) {
01957                 $payload = $bits - 4 - $this->lengthIndicator($mode, $version);
01958                 switch($mode) {
01959                         case QR_MODE_NM: {
01960                                 $chunks = (int)($payload / 10);
01961                                 $remain = $payload - $chunks * 10;
01962                                 $size = $chunks * 3;
01963                                 if ($remain >= 7) {
01964                                         $size += 2;
01965                                 } elseif ($remain >= 4) {
01966                                         $size += 1;
01967                                 }
01968                                 break;
01969                         }
01970                         case QR_MODE_AN: {
01971                                 $chunks = (int)($payload / 11);
01972                                 $remain = $payload - $chunks * 11;
01973                                 $size = $chunks * 2;
01974                                 if ($remain >= 6) {
01975                                         ++$size;
01976                                 }
01977                                 break;
01978                         }
01979                         case QR_MODE_8B: {
01980                                 $size = (int)($payload / 8);
01981                                 break;
01982                         }
01983                         case QR_MODE_KJ: {
01984                                 $size = (int)(($payload / 13) * 2);
01985                                 break;
01986                         }
01987                         case QR_MODE_ST: {
01988                                 $size = (int)($payload / 8);
01989                                 break;
01990                         }
01991                         default: {
01992                                 $size = 0;
01993                                 break;
01994                         }
01995                 }
01996                 $maxsize = $this->maximumWords($mode, $version);
01997                 if ($size < 0) {
01998                         $size = 0;
01999                 }
02000                 if ($size > $maxsize) {
02001                         $size = $maxsize;
02002                 }
02003                 return $size;
02004         }
02005 
02011          protected function createBitStream($items) {
02012                 $total = 0;
02013                 foreach ($items as $key => $item) {
02014                         $items[$key] = $this->encodeBitStream($item, $this->version);
02015                         $bits = count($items[$key]['bstream']);
02016                         $total += $bits;
02017                 }
02018                 return array($items, $total);
02019         }
02020 
02026          protected function convertData($items) {
02027                 $ver = $this->estimateVersion($items);
02028                 if ($ver > $this->version) {
02029                         $this->version = $ver;
02030                 }
02031                 for (;;) {
02032                         $cbs = $this->createBitStream($items);
02033                         $items = $cbs[0];
02034                         $bits = $cbs[1];
02035                         if ($bits < 0) {
02036                                 return -1;
02037                         }
02038                         $ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
02039                         if ($ver < 0) {
02040                                 return -1;
02041                         } elseif ($ver > $this->version) {
02042                                 $this->version = $ver;
02043                         } else {
02044                                 break;
02045                         }
02046                 }
02047                 return $items;
02048         }
02049 
02055          protected function appendPaddingBit($bstream) {
02056                 if (is_null($bstream)) {
02057                         return null;
02058                 }
02059                 $bits = count($bstream);
02060                 $maxwords = $this->getDataLength($this->version, $this->level);
02061                 $maxbits = $maxwords * 8;
02062                 if ($maxbits == $bits) {
02063                         return $bstream;
02064                 }
02065                 if ($maxbits - $bits < 5) {
02066                         return $this->appendNum($bstream, $maxbits - $bits, 0);
02067                 }
02068                 $bits += 4;
02069                 $words = (int)(($bits + 7) / 8);
02070                 $padding = array();
02071                 $padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0);
02072                 $padlen = $maxwords - $words;
02073                 if ($padlen > 0) {
02074                         $padbuf = array();
02075                         for ($i=0; $i<$padlen; ++$i) {
02076                                 $padbuf[$i] = ($i&1)?0x11:0xec;
02077                         }
02078                         $padding = $this->appendBytes($padding, $padlen, $padbuf);
02079                 }
02080                 return $this->appendBitstream($bstream, $padding);
02081         }
02082 
02088          protected function mergeBitStream($items) {
02089                 $items = $this->convertData($items);
02090                 if (!is_array($items)) {
02091                         return null;
02092                 }
02093                 $bstream = array();
02094                 foreach ($items as $item) {
02095                         $bstream = $this->appendBitstream($bstream, $item['bstream']);
02096                 }
02097                 return $bstream;
02098         }
02099 
02105         protected function getBitStream($items) {
02106                 $bstream = $this->mergeBitStream($items);
02107                 return $this->appendPaddingBit($bstream);
02108         }
02109 
02115         protected function getByteStream($items) {
02116                 $bstream = $this->getBitStream($items);
02117                 return $this->bitstreamToByte($bstream);
02118         }
02119 
02120         // - - - - - - - - - - - - - - - - - - - - - - - - -
02121 
02122         // QRbitstream
02123 
02129          protected function allocate($setLength) {
02130                 return array_fill(0, $setLength, 0);
02131         }
02132 
02139          protected function newFromNum($bits, $num) {
02140                 $bstream = $this->allocate($bits);
02141                 $mask = 1 << ($bits - 1);
02142                 for ($i=0; $i<$bits; ++$i) {
02143                         if ($num & $mask) {
02144                                 $bstream[$i] = 1;
02145                         } else {
02146                                 $bstream[$i] = 0;
02147                         }
02148                         $mask = $mask >> 1;
02149                 }
02150                 return $bstream;
02151         }
02152 
02159          protected function newFromBytes($size, $data) {
02160                 $bstream = $this->allocate($size * 8);
02161                 $p=0;
02162                 for ($i=0; $i<$size; ++$i) {
02163                         $mask = 0x80;
02164                         for ($j=0; $j<8; ++$j) {
02165                                 if ($data[$i] & $mask) {
02166                                         $bstream[$p] = 1;
02167                                 } else {
02168                                         $bstream[$p] = 0;
02169                                 }
02170                                 $p++;
02171                                 $mask = $mask >> 1;
02172                         }
02173                 }
02174                 return $bstream;
02175         }
02176 
02183          protected function appendBitstream($bitstream, $append) {
02184                 if ((!is_array($append)) OR (count($append) == 0)) {
02185                         return $bitstream;
02186                 }
02187                 if (count($bitstream) == 0) {
02188                         return $append;
02189                 }
02190                 return array_values(array_merge($bitstream, $append));
02191         }
02192 
02200          protected function appendNum($bitstream, $bits, $num) {
02201                 if ($bits == 0) {
02202                         return 0;
02203                 }
02204                 $b = $this->newFromNum($bits, $num);
02205                 return $this->appendBitstream($bitstream, $b);
02206         }
02207 
02215          protected function appendBytes($bitstream, $size, $data) {
02216                 if ($size == 0) {
02217                         return 0;
02218                 }
02219                 $b = $this->newFromBytes($size, $data);
02220                 return $this->appendBitstream($bitstream, $b);
02221         }
02222 
02228          protected function bitstreamToByte($bstream) {
02229                 if (is_null($bstream)) {
02230                         return null;
02231                 }
02232                 $size = count($bstream);
02233                 if ($size == 0) {
02234                         return array();
02235                 }
02236                 $data = array_fill(0, (int)(($size + 7) / 8), 0);
02237                 $bytes = (int)($size / 8);
02238                 $p = 0;
02239                 for ($i=0; $i<$bytes; $i++) {
02240                         $v = 0;
02241                         for ($j=0; $j<8; $j++) {
02242                                 $v = $v << 1;
02243                                 $v |= $bstream[$p];
02244                                 $p++;
02245                         }
02246                         $data[$i] = $v;
02247                 }
02248                 if ($size & 7) {
02249                         $v = 0;
02250                         for ($j=0; $j<($size & 7); $j++) {
02251                                 $v = $v << 1;
02252                                 $v |= $bstream[$p];
02253                                 $p++;
02254                         }
02255                         $data[$bytes] = $v;
02256                 }
02257                 return $data;
02258         }
02259 
02260         // - - - - - - - - - - - - - - - - - - - - - - - - -
02261 
02262         // QRspec
02263 
02273          protected function qrstrset($srctab, $x, $y, $repl, $replLen=false) {
02274                 $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
02275                 return $srctab;
02276         }
02277 
02284         protected function getDataLength($version, $level) {
02285                 return $this->capacity[$version][QRCAP_WORDS] - $this->capacity[$version][QRCAP_EC][$level];
02286         }
02287 
02294         protected function getECCLength($version, $level){
02295                 return $this->capacity[$version][QRCAP_EC][$level];
02296         }
02297 
02303         protected function getWidth($version) {
02304                 return $this->capacity[$version][QRCAP_WIDTH];
02305         }
02306 
02312         protected function getRemainder($version) {
02313                 return $this->capacity[$version][QRCAP_REMINDER];
02314         }
02315 
02322         protected function getMinimumVersion($size, $level) {
02323                 for ($i=1; $i <= QRSPEC_VERSION_MAX; ++$i) {
02324                         $words = $this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level];
02325                         if ($words >= $size) {
02326                                 return $i;
02327                         }
02328                 }
02329                 return -1;
02330         }
02331 
02338         protected function lengthIndicator($mode, $version) {
02339                 if ($mode == QR_MODE_ST) {
02340                         return 0;
02341                 }
02342                 if ($version <= 9) {
02343                         $l = 0;
02344                 } elseif ($version <= 26) {
02345                         $l = 1;
02346                 } else {
02347                         $l = 2;
02348                 }
02349                 return $this->lengthTableBits[$mode][$l];
02350         }
02351 
02358         protected function maximumWords($mode, $version) {
02359                 if ($mode == QR_MODE_ST) {
02360                         return 3;
02361                 }
02362                 if ($version <= 9) {
02363                         $l = 0;
02364                 } else if ($version <= 26) {
02365                         $l = 1;
02366                 } else {
02367                         $l = 2;
02368                 }
02369                 $bits = $this->lengthTableBits[$mode][$l];
02370                 $words = (1 << $bits) - 1;
02371                 if ($mode == QR_MODE_KJ) {
02372                         $words *= 2; // the number of bytes is required
02373                 }
02374                 return $words;
02375         }
02376 
02384         protected function getEccSpec($version, $level, $spec) {
02385                 if (count($spec) < 5) {
02386                         $spec = array(0, 0, 0, 0, 0);
02387                 }
02388                 $b1 = $this->eccTable[$version][$level][0];
02389                 $b2 = $this->eccTable[$version][$level][1];
02390                 $data = $this->getDataLength($version, $level);
02391                 $ecc = $this->getECCLength($version, $level);
02392                 if ($b2 == 0) {
02393                         $spec[0] = $b1;
02394                         $spec[1] = (int)($data / $b1);
02395                         $spec[2] = (int)($ecc / $b1);
02396                         $spec[3] = 0;
02397                         $spec[4] = 0;
02398                 } else {
02399                         $spec[0] = $b1;
02400                         $spec[1] = (int)($data / ($b1 + $b2));
02401                         $spec[2] = (int)($ecc  / ($b1 + $b2));
02402                         $spec[3] = $b2;
02403                         $spec[4] = $spec[1] + 1;
02404                 }
02405                 return $spec;
02406         }
02407 
02415         protected function putAlignmentMarker($frame, $ox, $oy) {
02416                 $finder = array(
02417                         "\xa1\xa1\xa1\xa1\xa1",
02418                         "\xa1\xa0\xa0\xa0\xa1",
02419                         "\xa1\xa0\xa1\xa0\xa1",
02420                         "\xa1\xa0\xa0\xa0\xa1",
02421                         "\xa1\xa1\xa1\xa1\xa1"
02422                         );
02423                 $yStart = $oy - 2;
02424                 $xStart = $ox - 2;
02425                 for ($y=0; $y < 5; $y++) {
02426                         $frame = $this->qrstrset($frame, $xStart, $yStart+$y, $finder[$y]);
02427                 }
02428                 return $frame;
02429         }
02430 
02438          protected function putAlignmentPattern($version, $frame, $width) {
02439                 if ($version < 2) {
02440                         return $frame;
02441                 }
02442                 $d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0];
02443                 if ($d < 0) {
02444                         $w = 2;
02445                 } else {
02446                         $w = (int)(($width - $this->alignmentPattern[$version][0]) / $d + 2);
02447                 }
02448                 if ($w * $w - 3 == 1) {
02449                         $x = $this->alignmentPattern[$version][0];
02450                         $y = $this->alignmentPattern[$version][0];
02451                         $frame = $this->putAlignmentMarker($frame, $x, $y);
02452                         return $frame;
02453                 }
02454                 $cx = $this->alignmentPattern[$version][0];
02455                 $wo = $w - 1;
02456                 for ($x=1; $x < $wo; ++$x) {
02457                         $frame = $this->putAlignmentMarker($frame, 6, $cx);
02458                         $frame = $this->putAlignmentMarker($frame, $cx,  6);
02459                         $cx += $d;
02460                 }
02461                 $cy = $this->alignmentPattern[$version][0];
02462                 for ($y=0; $y < $wo; ++$y) {
02463                         $cx = $this->alignmentPattern[$version][0];
02464                         for ($x=0; $x < $wo; ++$x) {
02465                                 $frame = $this->putAlignmentMarker($frame, $cx, $cy);
02466                                 $cx += $d;
02467                         }
02468                         $cy += $d;
02469                 }
02470                 return $frame;
02471         }
02472 
02478         protected function getVersionPattern($version) {
02479                 if (($version < 7) OR ($version > QRSPEC_VERSION_MAX)) {
02480                         return 0;
02481                 }
02482                 return $this->versionPattern[($version - 7)];
02483         }
02484 
02491         protected function getFormatInfo($mask, $level) {
02492                 if (($mask < 0) OR ($mask > 7)) {
02493                         return 0;
02494                 }
02495                 if (($level < 0) OR ($level > 3)) {
02496                         return 0;
02497                 }
02498                 return $this->formatInfo[$level][$mask];
02499         }
02500 
02508         protected function putFinderPattern($frame, $ox, $oy) {
02509                 $finder = array(
02510                 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
02511                 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
02512                 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
02513                 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
02514                 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
02515                 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
02516                 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
02517                 );
02518                 for ($y=0; $y < 7; $y++) {
02519                         $frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
02520                 }
02521                 return $frame;
02522         }
02523 
02529         protected function createFrame($version) {
02530                 $width = $this->capacity[$version][QRCAP_WIDTH];
02531                 $frameLine = str_repeat ("\0", $width);
02532                 $frame = array_fill(0, $width, $frameLine);
02533                 // Finder pattern
02534                 $frame = $this->putFinderPattern($frame, 0, 0);
02535                 $frame = $this->putFinderPattern($frame, $width - 7, 0);
02536                 $frame = $this->putFinderPattern($frame, 0, $width - 7);
02537                 // Separator
02538                 $yOffset = $width - 7;
02539                 for ($y=0; $y < 7; ++$y) {
02540                         $frame[$y][7] = "\xc0";
02541                         $frame[$y][$width - 8] = "\xc0";
02542                         $frame[$yOffset][7] = "\xc0";
02543                         ++$yOffset;
02544                 }
02545                 $setPattern = str_repeat("\xc0", 8);
02546                 $frame = $this->qrstrset($frame, 0, 7, $setPattern);
02547                 $frame = $this->qrstrset($frame, $width-8, 7, $setPattern);
02548                 $frame = $this->qrstrset($frame, 0, $width - 8, $setPattern);
02549                 // Format info
02550                 $setPattern = str_repeat("\x84", 9);
02551                 $frame = $this->qrstrset($frame, 0, 8, $setPattern);
02552                 $frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8);
02553                 $yOffset = $width - 8;
02554                 for ($y=0; $y < 8; ++$y,++$yOffset) {
02555                         $frame[$y][8] = "\x84";
02556                         $frame[$yOffset][8] = "\x84";
02557                 }
02558                 // Timing pattern
02559                 $wo = $width - 15;
02560                 for ($i=1; $i < $wo; ++$i) {
02561                         $frame[6][7+$i] = chr(0x90 | ($i & 1));
02562                         $frame[7+$i][6] = chr(0x90 | ($i & 1));
02563                 }
02564                 // Alignment pattern
02565                 $frame = $this->putAlignmentPattern($version, $frame, $width);
02566                 // Version information
02567                 if ($version >= 7) {
02568                         $vinf = $this->getVersionPattern($version);
02569                         $v = $vinf;
02570                         for ($x=0; $x<6; ++$x) {
02571                                 for ($y=0; $y<3; ++$y) {
02572                                         $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
02573                                         $v = $v >> 1;
02574                                 }
02575                         }
02576                         $v = $vinf;
02577                         for ($y=0; $y<6; ++$y) {
02578                                 for ($x=0; $x<3; ++$x) {
02579                                         $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
02580                                         $v = $v >> 1;
02581                                 }
02582                         }
02583                 }
02584                 // and a little bit...
02585                 $frame[$width - 8][8] = "\x81";
02586                 return $frame;
02587         }
02588 
02594         protected function newFrame($version) {
02595                 if (($version < 1) OR ($version > QRSPEC_VERSION_MAX)) {
02596                         return NULL;
02597                 }
02598                 if (!isset($this->frames[$version])) {
02599                         $this->frames[$version] = $this->createFrame($version);
02600                 }
02601                 if (is_null($this->frames[$version])) {
02602                         return NULL;
02603                 }
02604                 return $this->frames[$version];
02605         }
02606 
02612          protected function rsBlockNum($spec) {
02613                 return ($spec[0] + $spec[3]);
02614         }
02615 
02621          protected function rsBlockNum1($spec) {
02622                 return $spec[0];
02623         }
02624 
02630          protected function rsDataCodes1($spec) {
02631                 return $spec[1];
02632         }
02633 
02639          protected function rsEccCodes1($spec) {
02640                 return $spec[2];
02641         }
02642 
02648          protected function rsBlockNum2($spec) {
02649                 return $spec[3];
02650         }
02651 
02657          protected function rsDataCodes2($spec) {
02658                 return $spec[4];
02659         }
02660 
02666          protected function rsEccCodes2($spec) {
02667                 return $spec[2];
02668         }
02669 
02675          protected function rsDataLength($spec) {
02676                 return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
02677         }
02678 
02684          protected function rsEccLength($spec) {
02685                 return ($spec[0] + $spec[3]) * $spec[2];
02686         }
02687 
02688         // - - - - - - - - - - - - - - - - - - - - - - - - -
02689 
02690         // QRrs
02691 
02702          protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
02703                 foreach ($this->rsitems as $rs) {
02704                         if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
02705                                 OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
02706                                 continue;
02707                         }
02708                         return $rs;
02709                 }
02710                 $rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
02711                 array_unshift($this->rsitems, $rs);
02712                 return $rs;
02713         }
02714 
02715         // - - - - - - - - - - - - - - - - - - - - - - - - -
02716 
02717         // QRrsItem
02718 
02725          protected function modnn($rs, $x) {
02726                 while ($x >= $rs['nn']) {
02727                         $x -= $rs['nn'];
02728                         $x = ($x >> $rs['mm']) + ($x & $rs['nn']);
02729                 }
02730                 return $x;
02731         }
02732 
02743         protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
02744                 // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
02745                 $rs = null;
02746                 // Check parameter ranges
02747                 if (($symsize < 0) OR ($symsize > 8)) {
02748                         return $rs;
02749                 }
02750                 if (($fcr < 0) OR ($fcr >= (1<<$symsize))) {
02751                         return $rs;
02752                 }
02753                 if (($prim <= 0) OR ($prim >= (1<<$symsize))) {
02754                         return $rs;
02755                 }
02756                 if (($nroots < 0) OR ($nroots >= (1<<$symsize))) {
02757                         return $rs;
02758                 }
02759                 if (($pad < 0) OR ($pad >= ((1<<$symsize) -1 - $nroots))) {
02760                         return $rs;
02761                 }
02762                 $rs = array();
02763                 $rs['mm'] = $symsize;
02764                 $rs['nn'] = (1 << $symsize) - 1;
02765                 $rs['pad'] = $pad;
02766                 $rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
02767                 $rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
02768                 // PHP style macro replacement ;)
02769                 $NN =& $rs['nn'];
02770                 $A0 =& $NN;
02771                 // Generate Galois field lookup tables
02772                 $rs['index_of'][0] = $A0; // log(zero) = -inf
02773                 $rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
02774                 $sr = 1;
02775                 for ($i=0; $i<$rs['nn']; ++$i) {
02776                         $rs['index_of'][$sr] = $i;
02777                         $rs['alpha_to'][$i] = $sr;
02778                         $sr <<= 1;
02779                         if ($sr & (1 << $symsize)) {
02780                                 $sr ^= $gfpoly;
02781                         }
02782                         $sr &= $rs['nn'];
02783                 }
02784                 if ($sr != 1) {
02785                         // field generator polynomial is not primitive!
02786                         return NULL;
02787                 }
02788                 // Form RS code generator polynomial from its roots
02789                 $rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
02790                 $rs['fcr'] = $fcr;
02791                 $rs['prim'] = $prim;
02792                 $rs['nroots'] = $nroots;
02793                 $rs['gfpoly'] = $gfpoly;
02794                 // Find prim-th root of 1, used in decoding
02795                 for ($iprim=1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
02796                         ; // intentional empty-body loop!
02797                 }
02798                 $rs['iprim'] = (int)($iprim / $prim);
02799                 $rs['genpoly'][0] = 1;
02800                 for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
02801                         $rs['genpoly'][$i+1] = 1;
02802                         // Multiply rs->genpoly[] by  @**(root + x)
02803                         for ($j = $i; $j > 0; --$j) {
02804                                 if ($rs['genpoly'][$j] != 0) {
02805                                         $rs['genpoly'][$j] = $rs['genpoly'][$j-1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
02806                                 } else {
02807                                         $rs['genpoly'][$j] = $rs['genpoly'][$j-1];
02808                                 }
02809                         }
02810                         // rs->genpoly[0] can never be zero
02811                         $rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
02812                 }
02813                 // convert rs->genpoly[] to index form for quicker encoding
02814                 for ($i = 0; $i <= $nroots; ++$i) {
02815                         $rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
02816                 }
02817                 return $rs;
02818         }
02819 
02827          protected function encode_rs_char($rs, $data, $parity) {
02828                 $MM       =& $rs['mm']; // bits per symbol
02829                 $NN       =& $rs['nn']; // the total number of symbols in a RS block
02830                 $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
02831                 $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
02832                 $GENPOLY  =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
02833                 $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
02834                 $FCR      =& $rs['fcr']; // first consecutive root, index form
02835                 $PRIM     =& $rs['prim']; // primitive element, index form
02836                 $IPRIM    =& $rs['iprim']; // prim-th root of 1, index form
02837                 $PAD      =& $rs['pad']; // the number of pad symbols in a block
02838                 $A0       =& $NN;
02839                 $parity = array_fill(0, $NROOTS, 0);
02840                 for ($i=0; $i < ($NN - $NROOTS - $PAD); $i++) {
02841                         $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
02842                         if ($feedback != $A0) {
02843                                 // feedback term is non-zero
02844                                 // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
02845                                 // always be for the polynomials constructed by init_rs()
02846                                 $feedback = $this->modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
02847                                 for ($j=1; $j < $NROOTS; ++$j) {
02848                                 $parity[$j] ^= $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
02849                                 }
02850                         }
02851                         // Shift
02852                         array_shift($parity);
02853                         if ($feedback != $A0) {
02854                                 array_push($parity, $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[0])]);
02855                         } else {
02856                                 array_push($parity, 0);
02857                         }
02858                 }
02859                 return $parity;
02860         }
02861 
02862 } // end QRcode class
02863 
02864 //============================================================+
02865 // END OF FILE
02866 //============================================================+
 All Data Structures Namespaces Files Functions Variables Enumerations