PHPIndex

This page lists files in the current directory. You can view content, get download/execute commands for Wget, Curl, or PowerShell, or filter the list using wildcards (e.g., `*.sh`).

ByteStream.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/ByteStream.php'
View Content
<?php
/**
 * ByteStream.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Estimate;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Spec;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\ByteStream
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
class ByteStream extends \Com\Tecnick\Barcode\Type\Square\QrCode\Encode
{
    /**
     * Encoding mode
     *
     * @var int
     */
    protected $hint = 2;

    /**
     * QR code version.
     * The Size of QRcode is defined as version. Version is an integer value from 1 to 40.
     * Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
     * So version 40 is 177*177 matrix.
     *
     * @var int
     */
    public $version = 0;

    /**
     * Error correction level
     *
     * @var int
     */
    protected $level = 0;

    /**
     * Initialize
     *
     * @param int $hint    Encoding mode
     * @param int $version Code version
     * @param int $level   Error Correction Level
     */
    public function __construct($hint, $version, $level)
    {
        $this->hint = $hint;
        $this->version = $version;
        $this->level = $level;
    }

    /**
     * Pack all bit streams padding bits into a byte array
     *
     * @param array $items items
     *
     * @return array padded merged byte stream
     */
    public function getByteStream($items)
    {
        return $this->bitstreamToByte(
            $this->appendPaddingBit(
                $this->mergeBitStream($items)
            )
        );
    }

    /**
     * Convert bitstream to bytes
     *
     * @param array $bstream Original bitstream
     *
     * @return array of bytes
     */
    protected function bitstreamToByte($bstream)
    {
        $size = count($bstream);
        if ($size == 0) {
            return array();
        }
        $data = array_fill(0, (int)(($size + 7) / 8), 0);
        $bytes = (int)($size / 8);
        $pos = 0;
        for ($idx = 0; $idx < $bytes; ++$idx) {
            $val = 0;
            for ($jdx = 0; $jdx < 8; ++$jdx) {
                $val = $val << 1;
                $val |= $bstream[$pos];
                $pos++;
            }
            $data[$idx] = $val;
        }
        if ($size & 7) {
            $val = 0;
            for ($jdx = 0; $jdx < ($size & 7); ++$jdx) {
                $val = $val << 1;
                $val |= $bstream[$pos];
                $pos++;
            }
            $data[$bytes] = $val;
        }
        return $data;
    }

    /**
     * merge the bit stream
     *
     * @param array $items Items
     *
     * @return array bitstream
     */
    protected function mergeBitStream($items)
    {
        $items = $this->convertData($items);
        $bstream = array();
        foreach ($items as $item) {
            $bstream = $this->appendBitstream($bstream, $item['bstream']);
        }
        return $bstream;
    }

    /**
     * convertData
     *
     * @param array $items Items
     *
     * @return array items
     */
    protected function convertData($items)
    {
        $ver = $this->estimateVersion($items, $this->level);
        if ($ver > $this->version) {
            $this->version = $ver;
        }
        while (true) {
            $cbs = $this->createBitStream($items);
            $items = $cbs[0];
            $bits = $cbs[1];
            if ($bits < 0) {
                throw new BarcodeException('Negative Bits value');
            }
            $ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
            if ($ver > $this->version) {
                $this->version = $ver;
            } else {
                break;
            }
        }
        return $items;
    }

    /**
     * Create BitStream
     *
     * @param $items
     *
     * @return array of items and total bits
     */
    protected function createBitStream($items)
    {
        $total = 0;
        foreach ($items as $key => $item) {
            $items[$key] = $this->encodeBitStream($item, $this->version);
            $bits = count($items[$key]['bstream']);
            $total += $bits;
        }
        return array($items, $total);
    }

    /**
     * Encode BitStream
     *
     * @param array $inputitem
     * @param int   $version
     *
     * @return array input item
     */
    public function encodeBitStream($inputitem, $version)
    {
        $inputitem['bstream'] = array();
        $specObj = new Spec;
        $words = $specObj->maximumWords($inputitem['mode'], $version);
        if ($inputitem['size'] > $words) {
            $st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
            $st2 = $this->newInputItem(
                $inputitem['mode'],
                ($inputitem['size'] - $words),
                array_slice($inputitem['data'], $words)
            );
            $st1 = $this->encodeBitStream($st1, $version);
            $st2 = $this->encodeBitStream($st2, $version);
            $inputitem['bstream'] = array();
            $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
            $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
        } else {
            switch ($inputitem['mode']) {
                case Data::$encodingModes['NM']:
                    $inputitem = $this->encodeModeNum($inputitem, $version);
                    break;
                case Data::$encodingModes['AN']:
                    $inputitem = $this->encodeModeAn($inputitem, $version);
                    break;
                case Data::$encodingModes['8B']:
                    $inputitem = $this->encodeMode8($inputitem, $version);
                    break;
                case Data::$encodingModes['KJ']:
                    $inputitem = $this->encodeModeKanji($inputitem, $version);
                    break;
                case Data::$encodingModes['ST']:
                    $inputitem = $this->encodeModeStructure($inputitem);
                    break;
            }
        }
        return $inputitem;
    }

    /**
     * Append Padding Bit to bitstream
     *
     * @param array $bstream Bit stream
     *
     * @return array bitstream
     */
    protected function appendPaddingBit($bstream)
    {
        if (is_null($bstream)) {
            return null;
        }
        $bits = count($bstream);
        $specObj = new Spec;
        $maxwords = $specObj->getDataLength($this->version, $this->level);
        $maxbits = $maxwords * 8;
        if ($maxbits == $bits) {
            return $bstream;
        }
        if ($maxbits - $bits < 5) {
            return $this->appendNum($bstream, $maxbits - $bits, 0);
        }
        $bits += 4;
        $words = (int)(($bits + 7) / 8);
        $padding = array();
        $padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0);
        $padlen = $maxwords - $words;
        if ($padlen > 0) {
            $padbuf = array();
            for ($idx = 0; $idx < $padlen; ++$idx) {
                $padbuf[$idx] = (($idx & 1) ? 0x11 : 0xec);
            }
            $padding = $this->appendBytes($padding, $padlen, $padbuf);
        }
        return $this->appendBitstream($bstream, $padding);
    }
}
Data.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Data.php'
View Content
<?php
/**
 * Data.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Data
 *
 * Data for QrCode Barcode type class
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
class Data
{
    /**
     * Maximum QR Code version.
     */
    const QRSPEC_VERSION_MAX = 40;

    /**
     * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
     */
    const QRSPEC_WIDTH_MAX = 177;

    // -----------------------------------------------------

    /**
     * Matrix index to get width from $capacity array.
     */
    const QRCAP_WIDTH = 0;

    /**
     * Matrix index to get number of words from $capacity array.
     */
    const QRCAP_WORDS = 1;

    /**
     * Matrix index to get remainder from $capacity array.
     */
    const QRCAP_REMINDER = 2;

    /**
     * Matrix index to get error correction level from $capacity array.
     */
    const QRCAP_EC = 3;

    // -----------------------------------------------------

    // Structure (currently usupported)

    /**
     * Number of header bits for structured mode
     */
    const STRUCTURE_HEADER_BITS = 20;

    /**
     * Max number of symbols for structured mode
     */
    const MAX_STRUCTURED_SYMBOLS = 16;

    // -----------------------------------------------------

    // Masks

    /**
     * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
     */
    const N1 = 3;

    /**
     * Down point base value for case 2 mask pattern (module block of same color)
     */
    const N2 = 3;

    /**
     * Down point base value for case 3 mask pattern
     * (1:1:3:1:1(dark:bright:dark:bright:dark)pattern in a line or a column)
     */
    const N3 = 40;

    /**
     * Down point base value for case 4 mask pattern (ration of dark modules in whole)
     */
    const N4 = 10;

    /**
     * Encoding modes (characters which can be encoded in QRcode)
     *
     * NL : variable
     * NM : Encoding mode numeric (0-9). 3 characters are encoded to 10bit length.
     * AN : Encoding mode alphanumeric (0-9A-Z $%*+-./:) 45characters. 2 characters are encoded to 11bit length.
     * 8B : Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
     * KJ : Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length.
     * ST : Encoding mode STRUCTURED
     *
     * @var array
     */
    public static $encodingModes = array('NL' => -1, 'NM' => 0, 'AN' => 1, '8B' => 2, 'KJ' => 3, 'ST' => 4);
    
    /**
     * Array of valid error correction levels
     * QRcode has a function of an error correcting for miss reading that white is black.
     * Error correcting is defined in 4 level as below.
     * L : About 7% or less errors can be corrected.
     * M : About 15% or less errors can be corrected.
     * Q : About 25% or less errors can be corrected.
     * H : About 30% or less errors can be corrected.
     *
     * @var array
     */
    public static $errCorrLevels = array('L' => 0, 'M' => 1, 'Q' => 2, 'H' => 3);
    
    /**
     * Alphabet-numeric conversion table.
     *
     * @var array
     */
    public static $anTable = array(
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
        36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
         0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1, //
        -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
        25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  //
    );

    /**
     * Array Table of the capacity of symbols.
     * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
     *
     * @var array
     */
    public static $capacity = array(
        array(  0,    0, 0, array(   0,    0,    0,    0)), //
        array( 21,   26, 0, array(   7,   10,   13,   17)), //  1
        array( 25,   44, 7, array(  10,   16,   22,   28)), //
        array( 29,   70, 7, array(  15,   26,   36,   44)), //
        array( 33,  100, 7, array(  20,   36,   52,   64)), //
        array( 37,  134, 7, array(  26,   48,   72,   88)), //  5
        array( 41,  172, 7, array(  36,   64,   96,  112)), //
        array( 45,  196, 0, array(  40,   72,  108,  130)), //
        array( 49,  242, 0, array(  48,   88,  132,  156)), //
        array( 53,  292, 0, array(  60,  110,  160,  192)), //
        array( 57,  346, 0, array(  72,  130,  192,  224)), // 10
        array( 61,  404, 0, array(  80,  150,  224,  264)), //
        array( 65,  466, 0, array(  96,  176,  260,  308)), //
        array( 69,  532, 0, array( 104,  198,  288,  352)), //
        array( 73,  581, 3, array( 120,  216,  320,  384)), //
        array( 77,  655, 3, array( 132,  240,  360,  432)), // 15
        array( 81,  733, 3, array( 144,  280,  408,  480)), //
        array( 85,  815, 3, array( 168,  308,  448,  532)), //
        array( 89,  901, 3, array( 180,  338,  504,  588)), //
        array( 93,  991, 3, array( 196,  364,  546,  650)), //
        array( 97, 1085, 3, array( 224,  416,  600,  700)), // 20
        array(101, 1156, 4, array( 224,  442,  644,  750)), //
        array(105, 1258, 4, array( 252,  476,  690,  816)), //
        array(109, 1364, 4, array( 270,  504,  750,  900)), //
        array(113, 1474, 4, array( 300,  560,  810,  960)), //
        array(117, 1588, 4, array( 312,  588,  870, 1050)), // 25
        array(121, 1706, 4, array( 336,  644,  952, 1110)), //
        array(125, 1828, 4, array( 360,  700, 1020, 1200)), //
        array(129, 1921, 3, array( 390,  728, 1050, 1260)), //
        array(133, 2051, 3, array( 420,  784, 1140, 1350)), //
        array(137, 2185, 3, array( 450,  812, 1200, 1440)), // 30
        array(141, 2323, 3, array( 480,  868, 1290, 1530)), //
        array(145, 2465, 3, array( 510,  924, 1350, 1620)), //
        array(149, 2611, 3, array( 540,  980, 1440, 1710)), //
        array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
        array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
        array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
        array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
        array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
        array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
        array(177, 3706, 0, array( 750, 1372, 2040, 2430))  // 40
    );

    /**
     * Array Length indicator.
     *
     * @var array
     */
    public static $lengthTableBits = array(
        array(10, 12, 14),
        array( 9, 11, 13),
        array( 8, 16, 16),
        array( 8, 10, 12)
    );

    /**
     * Array Table of the error correction code (Reed-Solomon block).
     * See Table 12-16 (pp.30-36), JIS X0510:2004.
     *
     * @var array
     */
    public static $eccTable = array(
        array(array( 0,  0), array( 0,  0), array( 0,  0), array( 0,  0)), //
        array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //  1
        array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //
        array(array( 1,  0), array( 1,  0), array( 2,  0), array( 2,  0)), //
        array(array( 1,  0), array( 2,  0), array( 2,  0), array( 4,  0)), //
        array(array( 1,  0), array( 2,  0), array( 2,  2), array( 2,  2)), //  5
        array(array( 2,  0), array( 4,  0), array( 4,  0), array( 4,  0)), //
        array(array( 2,  0), array( 4,  0), array( 2,  4), array( 4,  1)), //
        array(array( 2,  0), array( 2,  2), array( 4,  2), array( 4,  2)), //
        array(array( 2,  0), array( 3,  2), array( 4,  4), array( 4,  4)), //
        array(array( 2,  2), array( 4,  1), array( 6,  2), array( 6,  2)), // 10
        array(array( 4,  0), array( 1,  4), array( 4,  4), array( 3,  8)), //
        array(array( 2,  2), array( 6,  2), array( 4,  6), array( 7,  4)), //
        array(array( 4,  0), array( 8,  1), array( 8,  4), array(12,  4)), //
        array(array( 3,  1), array( 4,  5), array(11,  5), array(11,  5)), //
        array(array( 5,  1), array( 5,  5), array( 5,  7), array(11,  7)), // 15
        array(array( 5,  1), array( 7,  3), array(15,  2), array( 3, 13)), //
        array(array( 1,  5), array(10,  1), array( 1, 15), array( 2, 17)), //
        array(array( 5,  1), array( 9,  4), array(17,  1), array( 2, 19)), //
        array(array( 3,  4), array( 3, 11), array(17,  4), array( 9, 16)), //
        array(array( 3,  5), array( 3, 13), array(15,  5), array(15, 10)), // 20
        array(array( 4,  4), array(17,  0), array(17,  6), array(19,  6)), //
        array(array( 2,  7), array(17,  0), array( 7, 16), array(34,  0)), //
        array(array( 4,  5), array( 4, 14), array(11, 14), array(16, 14)), //
        array(array( 6,  4), array( 6, 14), array(11, 16), array(30,  2)), //
        array(array( 8,  4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
        array(array(10,  2), array(19,  4), array(28,  6), array(33,  4)), //
        array(array( 8,  4), array(22,  3), array( 8, 26), array(12, 28)), //
        array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
        array(array( 7,  7), array(21,  7), array( 1, 37), array(19, 26)), //
        array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
        array(array(13,  3), array( 2, 29), array(42,  1), array(23, 28)), //
        array(array(17,  0), array(10, 23), array(10, 35), array(19, 35)), //
        array(array(17,  1), array(14, 21), array(29, 19), array(11, 46)), //
        array(array(13,  6), array(14, 23), array(44,  7), array(59,  1)), //
        array(array(12,  7), array(12, 26), array(39, 14), array(22, 41)), // 35
        array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
        array(array(17,  4), array(29, 14), array(49, 10), array(24, 46)), //
        array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
        array(array(20,  4), array(40,  7), array(43, 22), array(10, 67)), //
        array(array(19,  6), array(18, 31), array(34, 34), array(20, 61))  // 40
    );

    /**
     * Array Positions of alignment patterns.
     * This array includes only the second and the third position of the alignment patterns.
     * Rest of them can be calculated from the distance between them.
     * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
     *
     * @var array
     */
    public static $alignmentPattern = array(
        array( 0,  0),
        array( 0,  0), array(18,  0), array(22,  0), array(26,  0), array(30,  0), //  1- 5
        array(34,  0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), //  6-10
        array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
        array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
        array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
        array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
        array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
        array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58)  // 35-40
    );

    /**
     * Array Version information pattern (BCH coded).
     * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
     * size: [QRSPEC_VERSION_MAX - 6]
     *
     * @var array
     */
    public static $versionPattern = array(
        0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
        0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
        0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
        0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
        0x27541, 0x28c69
    );

    /**
     * Array Format information
     *
     * @var array
     */
    public static $formatInfo = array(
        array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
        array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
        array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
        array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)  //
    );
}
Encode.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Encode.php'
View Content
<?php
/**
 * Encode.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Encode
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class Encode extends \Com\Tecnick\Barcode\Type\Square\QrCode\EncodingMode
{
    /**
     * encode Mode Num
     *
     * @param array $inputitem
     * @param int   $version
     *
     * @return array input item
     */
    protected function encodeModeNum($inputitem, $version)
    {
        $words = (int)($inputitem['size'] / 3);
        $inputitem['bstream'] = array();
        $val = 0x1;
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
        $inputitem['bstream'] = $this->appendNum(
            $inputitem['bstream'],
            $this->getLengthIndicator(Data::$encodingModes['NM'], $version),
            $inputitem['size']
        );
        for ($i=0; $i < $words; ++$i) {
            $val  = (ord($inputitem['data'][$i*3  ]) - ord('0')) * 100;
            $val += (ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
            $val += (ord($inputitem['data'][$i*3+2]) - ord('0'));
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
        }
        if ($inputitem['size'] - $words * 3 == 1) {
            $val = ord($inputitem['data'][$words*3]) - ord('0');
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
        } elseif (($inputitem['size'] - ($words * 3)) == 2) {
            $val  = (ord($inputitem['data'][$words*3  ]) - ord('0')) * 10;
            $val += (ord($inputitem['data'][$words*3+1]) - ord('0'));
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
        }
        return $inputitem;
    }

    /**
     * encode Mode An
     *
     * @param array $inputitem
     * @param int   $version
     *
     * @return array input item
     */
    protected function encodeModeAn($inputitem, $version)
    {
        $words = (int)($inputitem['size'] / 2);
        $inputitem['bstream'] = array();
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
        $inputitem['bstream'] = $this->appendNum(
            $inputitem['bstream'],
            $this->getLengthIndicator(Data::$encodingModes['AN'], $version),
            $inputitem['size']
        );
        for ($idx = 0; $idx < $words; ++$idx) {
            $val  = (int)($this->lookAnTable(ord($inputitem['data'][($idx * 2)])) * 45);
            $val += (int)($this->lookAnTable(ord($inputitem['data'][($idx * 2)+1])));
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
        }
        if ($inputitem['size'] & 1) {
            $val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
        }
        return $inputitem;
    }

    /**
     * encode Mode 8
     *
     * @param array $inputitem
     * @param int   $version
     *
     * @return array input item
     */
    protected function encodeMode8($inputitem, $version)
    {
        $inputitem['bstream'] = array();
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
        $inputitem['bstream'] = $this->appendNum(
            $inputitem['bstream'],
            $this->getLengthIndicator(Data::$encodingModes['8B'], $version),
            $inputitem['size']
        );
        for ($idx = 0; $idx < $inputitem['size']; ++$idx) {
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$idx]));
        }
        return $inputitem;
    }

    /**
     * encode Mode Kanji
     *
     * @param array $inputitem
     * @param int   $version
     *
     * @return array input item
     */
    protected function encodeModeKanji($inputitem, $version)
    {
        $inputitem['bstream'] = array();
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
        $inputitem['bstream'] = $this->appendNum(
            $inputitem['bstream'],
            $this->getLengthIndicator(Data::$encodingModes['KJ'], $version),
            (int)($inputitem['size'] / 2)
        );
        for ($idx = 0; $idx < $inputitem['size']; $idx += 2) {
            $val = (ord($inputitem['data'][$idx]) << 8) | ord($inputitem['data'][($idx + 1)]);
            if ($val <= 0x9ffc) {
                $val -= 0x8140;
            } else {
                $val -= 0xc140;
            }
            $val = ($val & 0xff) + (($val >> 8) * 0xc0);
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
        }
        return $inputitem;
    }

    /**
     * encode Mode Structure
     *
     * @param array $inputitem
     *
     * @return array input item
     */
    protected function encodeModeStructure($inputitem)
    {
        $inputitem['bstream'] = array();
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
        $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
        return $inputitem;
    }
}
Encoder.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Encoder.php'
View Content
<?php
/**
 * Encoder.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Spec;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Encoder
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
class Encoder extends \Com\Tecnick\Barcode\Type\Square\QrCode\Init
{
    /**
     * Data code
     *
     * @var array
     */
    protected $datacode = array();

    /**
     * Error correction code
     *
     * @var array
     */
    protected $ecccode = array();

    /**
     * Blocks
     *
     * @var array
     */
    protected $blocks;

    /**
     * Reed-Solomon blocks
     *
     * @var array
     */
    protected $rsblocks = array(); //of RSblock

    /**
     * Counter
     *
     * @var int
     */
    protected $count;

    /**
     * Data length
     *
     * @var int
     */
    protected $dataLength;

    /**
     * Error correction length
     *
     * @var int
     */
    protected $eccLength;

    /**
     * Value bv1
     *
     * @var int
     */
    protected $bv1;

    /**
     * Width.
     *
     * @var int
     */
    protected $width;

    /**
     * Frame
     *
     * @var array
     */
    protected $frame;

    /**
     * Horizontal bit position
     *
     * @var int
     */
    protected $xpos;

    /**
     * Vertical bit position
     *
     * @var int
     */
    protected $ypos;

    /**
     * Direction
     *
     * @var int
     */
    protected $dir;

    /**
     * Single bit value
     *
     * @var int
     */
    protected $bit;

    /**
     * Reed-Solomon items
     *
     * @va array
     */
    protected $rsitems = array();

    /**
     * Encode mask
     *
     * @param int   $maskNo   Mask number (masking mode)
     * @param array $datacode Data code to encode
     *
     * @return array Encoded Mask
     */
    public function encodeMask($maskNo, $datacode)
    {
        // initialize values
        $this->datacode = $datacode;
        $spec = $this->spc->getEccSpec($this->version, $this->level, array(0, 0, 0, 0, 0));
        $this->bv1 = $this->spc->rsBlockNum1($spec);
        $this->dataLength = $this->spc->rsDataLength($spec);
        $this->eccLength = $this->spc->rsEccLength($spec);
        $this->ecccode = array_fill(0, $this->eccLength, 0);
        $this->blocks = $this->spc->rsBlockNum($spec);
        $this->init($spec);
        $this->count = 0;
        $this->width = $this->spc->getWidth($this->version);
        $this->frame = $this->spc->createFrame($this->version);
        $this->xpos = ($this->width - 1);
        $this->ypos = ($this->width - 1);
        $this->dir = -1;
        $this->bit = -1;
        
        // interleaved data and ecc codes
        for ($idx = 0; $idx < ($this->dataLength + $this->eccLength); $idx++) {
            $code = $this->getCode();
            $bit = 0x80;
            for ($jdx = 0; $jdx < 8; $jdx++) {
                $addr = $this->getNextPosition();
                $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
                $bit = $bit >> 1;
            }
        }

        // remainder bits
        $rbits = $this->spc->getRemainder($this->version);
        for ($idx = 0; $idx < $rbits; $idx++) {
            $addr = $this->getNextPosition();
            $this->setFrameAt($addr, 0x02);
        }

        // masking
        $this->runLength = array_fill(0, (Data::QRSPEC_WIDTH_MAX + 1), 0);
        if ($maskNo < 0) {
            if ($this->qr_find_best_mask) {
                $mask = $this->mask($this->width, $this->frame, $this->level);
            } else {
                $mask = $this->makeMask($this->width, $this->frame, (intval($this->qr_default_mask) % 8), $this->level);
            }
        } else {
            $mask = $this->makeMask($this->width, $this->frame, $maskNo, $this->level);
        }
        if ($mask == null) {
            throw new BarcodeException('Null Mask');
        }
        return $mask;
    }

    /**
     * Return Reed-Solomon block code
     *
     * @return array rsblocks
     */
    protected function getCode()
    {
        if ($this->count < $this->dataLength) {
            $row = ($this->count % $this->blocks);
            $col = floor($this->count / $this->blocks);
            if ($col >= $this->rsblocks[0]['dataLength']) {
                $row += $this->bv1;
            }
            $ret = $this->rsblocks[$row]['data'][$col];
        } elseif ($this->count < ($this->dataLength + $this->eccLength)) {
            $row = (($this->count - $this->dataLength) % $this->blocks);
            $col = floor(($this->count - $this->dataLength) / $this->blocks);
            $ret = $this->rsblocks[$row]['ecc'][$col];
        } else {
            return 0;
        }
        ++$this->count;
        return $ret;
    }

    /**
     * Set frame value at specified position
     *
     * @param array $pos X,Y position
     * @param int   $val Value of the character to set
     */
    protected function setFrameAt($pos, $val)
    {
        $this->frame[$pos['y']][$pos['x']] = chr($val);
    }

    /**
     * Return the next frame position
     *
     * @return array of x,y coordinates
     */
    protected function getNextPosition()
    {
        do {
            if ($this->bit == -1) {
                $this->bit = 0;
                return array('x' => $this->xpos, 'y' => $this->ypos);
            }
            $xpos = $this->xpos;
            $ypos = $this->ypos;
            $wdt = $this->width;
            $this->getNextPositionB($xpos, $ypos, $wdt);
            if (($xpos < 0) || ($ypos < 0)) {
                throw new BarcodeException('Error getting next position');
            }
            $this->xpos = $xpos;
            $this->ypos = $ypos;
        } while (ord($this->frame[$ypos][$xpos]) & 0x80);

        return array('x' => $xpos, 'y' => $ypos);
    }

    /**
     * Internal cycle for getNextPosition
     *
     * @param int $xpos
     * @param int $ypos
     * @param int $wdt
     */
    protected function getNextPositionB(&$xpos, &$ypos, $wdt)
    {
        if ($this->bit == 0) {
            --$xpos;
            ++$this->bit;
        } else {
            ++$xpos;
            $ypos += $this->dir;
            --$this->bit;
        }
        if ($this->dir < 0) {
            if ($ypos < 0) {
                $ypos = 0;
                $xpos -= 2;
                $this->dir = 1;
                if ($xpos == 6) {
                    --$xpos;
                    $ypos = 9;
                }
            }
        } else {
            if ($ypos == $wdt) {
                $ypos = $wdt - 1;
                $xpos -= 2;
                $this->dir = -1;
                if ($xpos == 6) {
                    --$xpos;
                    $ypos -= 8;
                }
            }
        }
    }
}
EncodingMode.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/EncodingMode.php'
View Content
<?php
/**
 * EncodingMode.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\EncodingMode
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class EncodingMode extends \Com\Tecnick\Barcode\Type\Square\QrCode\InputItem
{
    /**
     * Get the encoding mode to use
     *
     * @param string $data Data
     * @param int    $pos  Position
     *
     * @return int mode
     */
    public function getEncodingMode($data, $pos)
    {
        if (!isset($data[$pos])) {
            return Data::$encodingModes['NL'];
        }
        if ($this->isDigitAt($data, $pos)) {
            return Data::$encodingModes['NM'];
        }
        if ($this->isAlphanumericAt($data, $pos)) {
            return Data::$encodingModes['AN'];
        }
        return $this->getEncodingModeKj($data, $pos);
    }

    /**
     * Get the encoding mode for KJ or 8B
     *
     * @param string $data Data
     * @param int    $pos  Position
     *
     * @return int mode
     */
    protected function getEncodingModeKj($data, $pos)
    {
        if (($this->hint == Data::$encodingModes['KJ']) && isset($data[($pos + 1)])) {
            $word = ((ord($data[$pos]) << 8) | ord($data[($pos + 1)]));
            if ((($word >= 0x8140) && ($word <= 0x9ffc)) || (($word >= 0xe040) && ($word <= 0xebbf))) {
                return Data::$encodingModes['KJ'];
            }
        }
        return Data::$encodingModes['8B'];
    }

    /**
     * Return true if the character at specified position is a number
     *
     * @param string $str Data
     * @param int    $pos Character position
     *
     * @return boolean
     */
    public function isDigitAt($str, $pos)
    {
        if (!isset($str[$pos])) {
            return false;
        }
        return ((ord($str[$pos]) >= ord('0')) && (ord($str[$pos]) <= ord('9')));
    }

    /**
     * Return true if the character at specified position is an alphanumeric character
     *
     * @param string $str Data
     * @param int    $pos Character position
     *
     * @return boolean
     */
    public function isAlphanumericAt($str, $pos)
    {
        if (!isset($str[$pos])) {
            return false;
        }
        return ($this->lookAnTable(ord($str[$pos])) >= 0);
    }

    /**
     * Look up the alphabet-numeric conversion table (see JIS X0510:2004, pp.19)
     *
     * @param int $chr Character value
     *
     * @return value
     */
    public function lookAnTable($chr)
    {
        return (($chr > 127) ? -1 : Data::$anTable[$chr]);
    }

    /**
     * Return the size of length indicator for the mode and version
     *
     * @param int $mode Encoding mode
     * @param int $version Version
     *
     * @return int the size of the appropriate length indicator (bits).
     */
    public function getLengthIndicator($mode)
    {
        if ($mode == Data::$encodingModes['ST']) {
            return 0;
        }
        if ($this->version <= 9) {
            $len = 0;
        } elseif ($this->version <= 26) {
            $len = 1;
        } else {
            $len = 2;
        }
        return Data::$lengthTableBits[$mode][$len];
    }

    /**
     * Append one bitstream to another
     *
     * @param array $bitstream Original bitstream
     * @param array $append    Bitstream to append
     *
     * @return array bitstream
     */
    protected function appendBitstream($bitstream, $append)
    {
        if ((!is_array($append)) || (count($append) == 0)) {
            return $bitstream;
        }
        if (count($bitstream) == 0) {
            return $append;
        }
        return array_values(array_merge($bitstream, $append));
    }

    /**
     * Append one bitstream created from number to another
     *
     * @param array $bitstream Original bitstream
     * @param int   $bits      Number of bits
     * @param int   $num       Number
     *
     * @return array bitstream
     */
    protected function appendNum($bitstream, $bits, $num)
    {
        if ($bits == 0) {
            return 0;
        }
        return $this->appendBitstream($bitstream, $this->newFromNum($bits, $num));
    }

    /**
     * Append one bitstream created from bytes to another
     *
     * @param array $bitstream Original bitstream
     * @param int   $size      Size
     * @param array $data      Bytes
     *
     * @return array bitstream
     */
    protected function appendBytes($bitstream, $size, $data)
    {
        if ($size == 0) {
            return 0;
        }
        return $this->appendBitstream($bitstream, $this->newFromBytes($size, $data));
    }

    /**
     * Return new bitstream from number
     *
     * @param int $bits Number of bits
     * @param int $num  Number
     *
     * @return array bitstream
     */
    protected function newFromNum($bits, $num)
    {
        $bstream = $this->allocate($bits);
        $mask = 1 << ($bits - 1);
        for ($idx = 0; $idx < $bits; ++$idx) {
            if ($num & $mask) {
                $bstream[$idx] = 1;
            } else {
                $bstream[$idx] = 0;
            }
            $mask = $mask >> 1;
        }
        return $bstream;
    }

    /**
     * Return new bitstream from bytes
     *
     * @param int   $size Size
     * @param array $data Bytes
     *
     * @return array bitstream
     */
    protected function newFromBytes($size, $data)
    {
        $bstream = $this->allocate($size * 8);
        $pval = 0;
        for ($idx = 0; $idx < $size; ++$idx) {
            $mask = 0x80;
            for ($jdx = 0; $jdx < 8; ++$jdx) {
                if ($data[$idx] & $mask) {
                    $bstream[$pval] = 1;
                } else {
                    $bstream[$pval] = 0;
                }
                $pval++;
                $mask = $mask >> 1;
            }
        }
        return $bstream;
    }

    /**
     * Return an array with zeros
     *
     * @param int $setLength Array size
     *
     * @return array
     */
    protected function allocate($setLength)
    {
        return array_fill(0, $setLength, 0);
    }
}
Estimate.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Estimate.php'
View Content
<?php
/**
 * Estimate.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Estimate
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class Estimate
{
    /**
     * estimateBitsModeNum
     *
     * @param int $size
     *
     * @return int number of bits
     */
    public function estimateBitsModeNum($size)
    {
        $wdt = (int)($size / 3);
        $bits = ($wdt * 10);
        switch ($size - ($wdt * 3)) {
            case 1:
                $bits += 4;
                break;
            case 2:
                $bits += 7;
                break;
        }
        return $bits;
    }

    /**
     * estimateBitsModeAn
     *
     * @param int $size
     *
     * @return int number of bits
     */
    public function estimateBitsModeAn($size)
    {
        $bits = (int)($size * 5.5); // (size / 2 ) * 11
        if ($size & 1) {
            $bits += 6;
        }
        return $bits;
    }

    /**
     * estimateBitsMode8
     *
     * @param int $size
     *
     * @return int number of bits
     */
    public function estimateBitsMode8($size)
    {
        return (int)($size * 8);
    }

    /**
     * estimateBitsModeKanji
     *
     * @param int $size
     *
     * @return int number of bits
     */
    public function estimateBitsModeKanji($size)
    {
        return (int)($size * 6.5); // (size / 2 ) * 13
    }

    /**
     * Estimate version
     *
     * @param array $items
     * @param int   $level
     *
     * @return int version
     */
    public function estimateVersion($items, $level)
    {
        $version = 0;
        $prev = 0;
        do {
            $prev = $version;
            $bits = $this->estimateBitStreamSize($items, $prev);
            $version = $this->getMinimumVersion((int)(($bits + 7) / 8), $level);
            if ($version < 0) {
                return -1;
            }
        } while ($version > $prev);
        return $version;
    }

    /**
     * Return a version number that satisfies the input code length.
     *
     * @param int $size  Input code length (bytes)
     * @param int $level Error correction level
     *
     * @return int version number
     *
     * @throws BarcodeException
     */
    protected function getMinimumVersion($size, $level)
    {
        for ($idx = 1; $idx <= Data::QRSPEC_VERSION_MAX; ++$idx) {
            $words = (Data::$capacity[$idx][Data::QRCAP_WORDS] - Data::$capacity[$idx][Data::QRCAP_EC][$level]);
            if ($words >= $size) {
                return $idx;
            }
        }
        throw new BarcodeException(
            'The size of input data is greater than Data::QR capacity, try to lower the error correction mode'
        );
    }

    /**
     * estimateBitStreamSize
     *
     * @param array $items
     * @param int   $version
     *
     * @return int bits
     */
    protected function estimateBitStreamSize($items, $version)
    {
        $bits = 0;
        if ($version == 0) {
            $version = 1;
        }
        foreach ($items as $item) {
            switch ($item['mode']) {
                case Data::$encodingModes['NM']:
                    $bits = $this->estimateBitsModeNum($item['size']);
                    break;
                case Data::$encodingModes['AN']:
                    $bits = $this->estimateBitsModeAn($item['size']);
                    break;
                case Data::$encodingModes['8B']:
                    $bits = $this->estimateBitsMode8($item['size']);
                    break;
                case Data::$encodingModes['KJ']:
                    $bits = $this->estimateBitsModeKanji($item['size']);
                    break;
                case Data::$encodingModes['ST']:
                    return Data::STRUCTURE_HEADER_BITS;
                default:
                    return 0;
            }
            $len = $this->getLengthIndicator($item['mode'], $version);
            $mod = 1 << $len;
            $num = (int)(($item['size'] + $mod - 1) / $mod);
            $bits += $num * (4 + $len);
        }
        return $bits;
    }
}
Init.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Init.php'
View Content
<?php
/**
 * Init.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Spec;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Init
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class Init extends \Com\Tecnick\Barcode\Type\Square\QrCode\Mask
{
    /**
     * Initialize code
     *
     * @param array $spec Array of ECC specification
     */
    protected function init($spec)
    {
        $dlv = $this->spc->rsDataCodes1($spec);
        $elv = $this->spc->rsEccCodes1($spec);
        $rsv = $this->initRs(8, 0x11d, 0, 1, $elv, 255 - $dlv - $elv);
        $blockNo = 0;
        $dataPos = 0;
        $eccPos = 0;
        $endfor = $this->spc->rsBlockNum1($spec);
        $this->initLoop($endfor, $dlv, $elv, $rsv, $eccPos, $blockNo, $dataPos, $ecc);
        if ($this->spc->rsBlockNum2($spec) == 0) {
            return;
        }
        $dlv = $this->spc->rsDataCodes2($spec);
        $elv = $this->spc->rsEccCodes2($spec);
        $rsv = $this->initRs(8, 0x11d, 0, 1, $elv, 255 - $dlv - $elv);
        if ($rsv == null) {
            throw new BarcodeException('Empty RS');
        }
        $endfor = $this->spc->rsBlockNum2($spec);
        $this->initLoop($endfor, $dlv, $elv, $rsv, $eccPos, $blockNo, $dataPos, $ecc);
    }

    /**
     * Internal loop for init
     *
     * @param int $endfor
     * @param int $dlv
     * @param int $elv
     * @param int $rsv
     * @param int $eccPos
     * @param int $blockNo
     * @param int $dataPos
     * @param int $ecc
     */
    protected function initLoop($endfor, $dlv, $elv, $rsv, &$eccPos, &$blockNo, &$dataPos, &$ecc)
    {
        for ($idx = 0; $idx < $endfor; ++$idx) {
            $ecc = array_slice($this->ecccode, $eccPos);
            $this->rsblocks[$blockNo] = array();
            $this->rsblocks[$blockNo]['dataLength'] = $dlv;
            $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
            $this->rsblocks[$blockNo]['eccLength'] = $elv;
            $ecc = $this->encodeRsChar($rsv, $this->rsblocks[$blockNo]['data'], $ecc);
            $this->rsblocks[$blockNo]['ecc'] = $ecc;
            $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
            $dataPos += $dlv;
            $eccPos += $elv;
            $blockNo++;
        }
    }

    /**
     * Initialize a Reed-Solomon codec and add it to existing rsitems
     *
     * @param int $symsize Symbol size, bits
     * @param int $gfpoly  Field generator polynomial coefficients
     * @param int $fcr     First root of RS code generator polynomial, index form
     * @param int $prim    Primitive element to generate polynomial roots
     * @param int $nroots  RS code generator polynomial degree (number of roots)
     * @param int $pad     Padding bytes at front of shortened block
     *
     * @return array Array of RS values:
     *          mm = Bits per symbol;
     *          nn = Symbols per block;
     *          alpha_to = log lookup table array;
     *          index_of = Antilog lookup table array;
     *          genpoly = Generator polynomial array;
     *          nroots = Number of generator;
     *          roots = number of parity symbols;
     *          fcr = First consecutive root, index form;
     *          prim = Primitive element, index form;
     *          iprim = prim-th root of 1, index form;
     *          pad = Padding bytes in shortened block;
     *          gfpoly.
     */
    protected function initRs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
    {
        foreach ($this->rsitems as $rsv) {
            if (($rsv['pad'] != $pad)
                || ($rsv['nroots'] != $nroots)
                || ($rsv['mm'] != $symsize)
                || ($rsv['gfpoly'] != $gfpoly)
                || ($rsv['fcr'] != $fcr)
                || ($rsv['prim'] != $prim)) {
                continue;
            }
            return $rsv;
        }
        $rsv = $this->initRsChar($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
        array_unshift($this->rsitems, $rsv);
        return $rsv;
    }

    /**
     * modnn
     *
     * @param array $rsv  RS values
     * @param int   $xpos X position
     *
     * @return int X position
     */
    protected function modnn($rsv, $xpos)
    {
        while ($xpos >= $rsv['nn']) {
            $xpos -= $rsv['nn'];
            $xpos = (($xpos >> $rsv['mm']) + ($xpos & $rsv['nn']));
        }
        return $xpos;
    }

    /**
     * Check the params for the initRsChar and throws an exception in case of error.
     *
     * @param int $symsize Symbol size, bits
     * @param int $fcr     First root of RS code generator polynomial, index form
     * @param int $prim    Primitive element to generate polynomial roots
     *
     * @throws BarcodeException in case of error
     */
    protected function checkRsCharParamsA($symsize, $fcr, $prim)
    {
        $shfsymsize = (1 << $symsize);
        if (($symsize < 0)
            || ($symsize > 8)
            || ($fcr < 0)
            || ($fcr >= $shfsymsize)
            || ($prim <= 0)
            || ($prim >= $shfsymsize)
        ) {
            throw new BarcodeException('Invalid parameters');
        }
    }

    /**
     * Check the params for the initRsChar and throws an exception in case of error.
     *
     * @param int $symsize Symbol size, bits
     * @param int $nroots  RS code generator polynomial degree (number of roots)
     * @param int $pad     Padding bytes at front of shortened block
     *
     * @throws BarcodeException in case of error
     */
    protected function checkRsCharParamsB($symsize, $nroots, $pad)
    {
        $shfsymsize = (1 << $symsize);
        if (($nroots < 0)
            || ($nroots >= $shfsymsize)
            || ($pad < 0)
            || ($pad >= ($shfsymsize - 1 - $nroots))
        ) {
            throw new BarcodeException('Invalid parameters');
        }
    }
    /**
     * Initialize a Reed-Solomon codec and returns an array of values.
     *
     * @param int $symsize Symbol size, bits
     * @param int $gfpoly  Field generator polynomial coefficients
     * @param int $fcr     First root of RS code generator polynomial, index form
     * @param int $prim    Primitive element to generate polynomial roots
     * @param int $nroots  RS code generator polynomial degree (number of roots)
     * @param int $pad     Padding bytes at front of shortened block
     *
     * @return array Array of RS values:
     *          mm = Bits per symbol;
     *          nn = Symbols per block;
     *          alpha_to = log lookup table array;
     *          index_of = Antilog lookup table array;
     *          genpoly = Generator polynomial array;
     *          nroots = Number of generator;
     *          roots = number of parity symbols;
     *          fcr = First consecutive root, index form;
     *          prim = Primitive element, index form;
     *          iprim = prim-th root of 1, index form;
     *          pad = Padding bytes in shortened block;
     *          gfpoly.
     */
    protected function initRsChar($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
    {
        $this->checkRsCharParamsA($symsize, $fcr, $prim);
        $this->checkRsCharParamsB($symsize, $nroots, $pad);
        $rsv = array();
        $rsv['mm'] = $symsize;
        $rsv['nn'] = ((1 << $symsize) - 1);
        $rsv['pad'] = $pad;
        $rsv['alpha_to'] = array_fill(0, ($rsv['nn'] + 1), 0);
        $rsv['index_of'] = array_fill(0, ($rsv['nn'] + 1), 0);
        // PHP style macro replacement
        $nnv =& $rsv['nn'];
        $azv =& $nnv;
        // Generate Galois field lookup tables
        $rsv['index_of'][0] = $azv; // log(zero) = -inf
        $rsv['alpha_to'][$azv] = 0; // alpha**-inf = 0
        $srv = 1;
        for ($idx = 0; $idx <$rsv['nn']; ++$idx) {
            $rsv['index_of'][$srv] = $idx;
            $rsv['alpha_to'][$idx] = $srv;
            $srv <<= 1;
            if ($srv & (1 << $symsize)) {
                $srv ^= $gfpoly;
            }
            $srv &= $rsv['nn'];
        }
        if ($srv != 1) {
            throw new BarcodeException('field generator polynomial is not primitive!');
        }
        // form RS code generator polynomial from its roots
        $rsv['genpoly'] = array_fill(0, ($nroots + 1), 0);
        $rsv['fcr'] = $fcr;
        $rsv['prim'] = $prim;
        $rsv['nroots'] = $nroots;
        $rsv['gfpoly'] = $gfpoly;
        // find prim-th root of 1, used in decoding
        for ($iprim = 1; ($iprim % $prim) != 0; $iprim += $rsv['nn']) {
            ; // intentional empty-body loop!
        }
        $rsv['iprim'] = (int)($iprim / $prim);
        $rsv['genpoly'][0] = 1;
        for ($idx = 0, $root = ($fcr * $prim); $idx < $nroots; ++$idx, $root += $prim) {
            $rsv['genpoly'][($idx + 1)] = 1;
            // multiply rs->genpoly[] by  @**(root + x)
            for ($jdx = $idx; $jdx > 0; --$jdx) {
                if ($rsv['genpoly'][$jdx] != 0) {
                    $rsv['genpoly'][$jdx] = ($rsv['genpoly'][($jdx - 1)]
                        ^ $rsv['alpha_to'][$this->modnn($rsv, $rsv['index_of'][$rsv['genpoly'][$jdx]] + $root)]);
                } else {
                    $rsv['genpoly'][$jdx] = $rsv['genpoly'][($jdx - 1)];
                }
            }
            // rs->genpoly[0] can never be zero
            $rsv['genpoly'][0] = $rsv['alpha_to'][$this->modnn($rsv, $rsv['index_of'][$rsv['genpoly'][0]] + $root)];
        }
        // convert rs->genpoly[] to index form for quicker encoding
        for ($idx = 0; $idx <= $nroots; ++$idx) {
            $rsv['genpoly'][$idx] = $rsv['index_of'][$rsv['genpoly'][$idx]];
        }
        return $rsv;
    }

    /**
     * Encode a Reed-Solomon codec and returns the parity array
     *
     * @param array $rsv    RS values
     * @param array $data   Data
     * @param array $parity Parity
     *
     * @return array Parity array
     */
    protected function encodeRsChar($rsv, $data, $parity)
    {
        // the total number of symbols in a RS block
        $nnv =& $rsv['nn'];
        // the address of an array of NN elements to convert Galois field elements
        // in index (log) form to polynomial form
        $alphato =& $rsv['alpha_to'];
        // the address of an array of NN elements to convert Galois field elements
        // in polynomial form to index (log) form
        $indexof =& $rsv['index_of'];
        // an array of NROOTS+1 elements containing the generator polynomial in index form
        $genpoly =& $rsv['genpoly'];
        // the number of roots in the RS code generator polynomial,
        // which is the same as the number of parity symbols in a block
        $nroots =& $rsv['nroots'];
        // the number of pad symbols in a block
        $pad =& $rsv['pad'];
        $azv =& $nnv;
        $parity = array_fill(0, $nroots, 0);
        for ($idx = 0; $idx < ($nnv - $nroots - $pad); ++$idx) {
            $feedback = $indexof[$data[$idx] ^ $parity[0]];
            if ($feedback != $azv) {
                // feedback term is non-zero
                // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
                // always be for the polynomials constructed by initRs()
                $feedback = $this->modnn($rsv, ($nnv - $genpoly[$nroots] + $feedback));
                for ($jdx = 1; $jdx < $nroots; ++$jdx) {
                    $parity[$jdx] ^= $alphato[$this->modnn($rsv, $feedback + $genpoly[($nroots - $jdx)])];
                }
            }
            // Shift
            array_shift($parity);
            if ($feedback != $azv) {
                array_push($parity, $alphato[$this->modnn($rsv, $feedback + $genpoly[0])]);
            } else {
                array_push($parity, 0);
            }
        }
        return $parity;
    }
}
InputItem.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/InputItem.php'
View Content
<?php
/**
 * InputItem.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\InputItem
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class InputItem extends \Com\Tecnick\Barcode\Type\Square\QrCode\Estimate
{
    /**
     * Append data to an input object.
     * The data is copied and appended to the input object.
     *
     * @param array $items Input items
     * @param int   $mode  Encoding mode.
     * @param int   $size  Size of data (byte).
     * @param array $data  Array of input data.
     *
     * @return array items
     */
    public function appendNewInputItem($items, $mode, $size, $data)
    {
        $newitem = $this->newInputItem($mode, $size, $data);
        if (!empty($newitem)) {
            $items[] = $newitem;
        }
        return $items;
    }

    /**
     * newInputItem
     *
     * @param int   $mode    Encoding mode.
     * @param int   $size    Size of data (byte).
     * @param array $data    Array of input data.
     * @param array $bstream Binary stream
     *
     * @return array input item
     */
    protected function newInputItem($mode, $size, $data, $bstream = null)
    {
        $setData = array_slice($data, 0, $size);
        if (count($setData) < $size) {
            $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
        }
        if (!$this->check($mode, $size, $setData)) {
            throw new BarcodeException('Invalid input item');
        }
        return array(
            'mode'    => $mode,
            'size'    => $size,
            'data'    => $setData,
            'bstream' => $bstream,
        );
    }

    /**
     * Validate the input data.
     *
     * @param int   $mode Encoding mode.
     * @param int   $size Size of data (byte).
     * @param array $data Data to validate
     *
     * @return boolean true in case of valid data, false otherwise
     */
    protected function check($mode, $size, $data)
    {
        if ($size <= 0) {
            return false;
        }
        switch ($mode) {
            case Data::$encodingModes['NM']:
                return $this->checkModeNum($size, $data);
            case Data::$encodingModes['AN']:
                return $this->checkModeAn($size, $data);
            case Data::$encodingModes['KJ']:
                return $this->checkModeKanji($size, $data);
            case Data::$encodingModes['8B']:
                return true;
            case Data::$encodingModes['ST']:
                return true;
        }
        return false;
    }

    /**
     * checkModeNum
     *
     * @param int $size
     * @param int $data
     *
     * @return boolean true or false
     */
    protected function checkModeNum($size, $data)
    {
        for ($idx = 0; $idx < $size; ++$idx) {
            if ((ord($data[$idx]) < ord('0')) || (ord($data[$idx]) > ord('9'))) {
                return false;
            }
        }
        return true;
    }

    /**
     * checkModeAn
     *
     * @param int $size
     * @param int $data
     *
     * @return boolean true or false
     */
    protected function checkModeAn($size, $data)
    {
        for ($idx = 0; $idx < $size; ++$idx) {
            if ($this->lookAnTable(ord($data[$idx])) == -1) {
                return false;
            }
        }
        return true;
    }

    /**
     * checkModeKanji
     *
     * @param int $size
     * @param int $data
     *
     * @return boolean true or false
     */
    protected function checkModeKanji($size, $data)
    {
        if ($size & 1) {
            return false;
        }
        for ($idx = 0; $idx < $size; $idx += 2) {
            $val = (ord($data[$idx]) << 8) | ord($data[($idx + 1)]);
            if (($val < 0x8140) || (($val > 0x9ffc) && ($val < 0xe040)) || ($val > 0xebbf)) {
                return false;
            }
        }
        return true;
    }
}
Mask.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Mask.php'
View Content
<?php
/**
 * Mask.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Spec;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Mask
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class Mask extends \Com\Tecnick\Barcode\Type\Square\QrCode\MaskNum
{
    /**
     * If false, checks all masks available,
     * otherwise the value indicates the number of masks to be checked, mask id are random
     *
     * @var int
     */
    protected $qr_find_from_random = false;

    /**
     * If true, estimates best mask (spec. default, but extremally slow;
     * set to false to significant performance boost but (propably) worst quality code
     *
     * @var bool
     */
    protected $qr_find_best_mask = true;

    /**
     * Default mask used when $this->qr_find_best_mask === false
     *
     * @var int
     */
    protected $qr_default_mask = 2;

    /**
     * Run length
     *
     * @var array
     */
    protected $runLength = array();

    /**
     * QR code version.
     * The Size of QRcode is defined as version. Version is an integer value from 1 to 40.
     * Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
     * So version 40 is 177*177 matrix.
     *
     * @var int
     */
    public $version = 0;

    /**
     * Error correction level
     *
     * @var int
     */
    protected $level = 0;

    /**
     * Spec class object
     *
     * @var \Com\Tecnick\Barcode\Type\Square\QrCode\Spec
     */
    protected $spc;

    /**
     * Initialize
     *
     * @param int  $version       Code version
     * @param int  $level         Error Correction Level
     * @param bool $random_mask   If false, checks all masks available,
     *                            otherwise the value indicates the number of masks to be checked, mask id are random
     * @param bool $best_mask     If true, estimates best mask (slow)
     * @param int  $default_mask  Default mask used when $fbm is false
     */
    public function __construct($version, $level, $random_mask = false, $best_mask = true, $default_mask = 2)
    {
        $this->version = $version;
        $this->level = $level;
        $this->qr_find_from_random = (bool)$random_mask;
        $this->qr_find_best_mask = (bool)$best_mask;
        $this->qr_default_mask = intval($default_mask);
        $this->spc = new Spec;
    }

    /**
     * Get the best mask
     *
     * @param int   $width Width
     * @param array $frame Frame
     * @param int   $level Error Correction lLevel
     *
     * @return array best mask
     */
    protected function mask($width, $frame, $level)
    {
        $minDemerit = PHP_INT_MAX;
        $bestMask = array();
        $checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
        if ($this->qr_find_from_random !== false) {
            $howManuOut = (8 - ($this->qr_find_from_random % 9));
            for ($idx = 0; $idx <  $howManuOut; ++$idx) {
                $remPos = rand(0, (count($checked_masks) - 1));
                unset($checked_masks[$remPos]);
                $checked_masks = array_values($checked_masks);
            }
        }
        $bestMask = $frame;
        foreach ($checked_masks as $idx) {
            $mask = array_fill(0, $width, str_repeat("\0", $width));
            $demerit = 0;
            $blacks = 0;
            $blacks  = $this->makeMaskNo($idx, $width, $frame, $mask);
            $blacks += $this->writeFormatInformation($width, $mask, $idx, $level);
            $blacks  = (int)(100 * $blacks / ($width * $width));
            $demerit = (int)((int)(abs($blacks - 50) / 5) * Data::N4);
            $demerit += $this->evaluateSymbol($width, $mask);
            if ($demerit < $minDemerit) {
                $minDemerit = $demerit;
                $bestMask = $mask;
            }
        }
        return $bestMask;
    }

    /**
     * Make a mask
     *
     * @param int   $width  Mask width
     * @param array $frame  Frame
     * @param int   $maskNo Mask number
     * @param int   $level  Error Correction level
     *
     * @return array mask
     */
    protected function makeMask($width, $frame, $maskNo, $level)
    {
        $this->makeMaskNo($maskNo, $width, $frame, $mask);
        $this->writeFormatInformation($width, $mask, $maskNo, $level);
        return $mask;
    }

    /**
     * Write Format Information on the frame and returns the number of black bits
     *
     * @param int   $width  Mask width
     * @param array $frame  Frame
     * @param int   $maskNo Mask number
     * @param int   $level  Error Correction level
     *
     * @return int blacks
     */
    protected function writeFormatInformation($width, &$frame, $maskNo, $level)
    {
        $blacks = 0;
        $spec = new Spec;
        $format =  $spec->getFormatInfo($maskNo, $level);
        for ($idx = 0; $idx < 8; ++$idx) {
            if ($format & 1) {
                $blacks += 2;
                $val = 0x85;
            } else {
                $val = 0x84;
            }
            $frame[8][($width - 1 - $idx)] = chr($val);
            if ($idx < 6) {
                $frame[$idx][8] = chr($val);
            } else {
                $frame[($idx + 1)][8] = chr($val);
            }
            $format = $format >> 1;
        }
        for ($idx = 0; $idx < 7; ++$idx) {
            if ($format & 1) {
                $blacks += 2;
                $val = 0x85;
            } else {
                $val = 0x84;
            }
            $frame[($width - 7 + $idx)][8] = chr($val);
            if ($idx == 0) {
                $frame[8][7] = chr($val);
            } else {
                $frame[8][(6 - $idx)] = chr($val);
            }
            $format = $format >> 1;
        }
        return $blacks;
    }

    /**
     * Evaluate Symbol
     *
     * @param int   $width Width
     * @param array $frame Frame
     *
     * @return int demerit
     */
    protected function evaluateSymbol($width, $frame)
    {
        for ($ypos = 0; $ypos < $width; ++$ypos) {
            $frameY = $frame[$ypos];
            if ($ypos > 0) {
                $frameYM = $frame[($ypos - 1)];
            } else {
                $frameYM = $frameY;
            }
            $demerit = $this->evaluateSymbolB($ypos, $width, $frameY, $frameYM);
        }
        for ($xpos = 0; $xpos < $width; ++$xpos) {
            $head = 0;
            $this->runLength[0] = 1;
            for ($ypos = 0; $ypos < $width; ++$ypos) {
                if (($ypos == 0) && (ord($frame[$ypos][$xpos]) & 1)) {
                    $this->runLength[0] = -1;
                    $head = 1;
                    $this->runLength[$head] = 1;
                } elseif ($ypos > 0) {
                    if ((ord($frame[$ypos][$xpos]) ^ ord($frame[($ypos - 1)][$xpos])) & 1) {
                        $head++;
                        $this->runLength[$head] = 1;
                    } else {
                        $this->runLength[$head]++;
                    }
                }
            }
            $demerit += $this->calcN1N3($head + 1);
        }
        return $demerit;
    }

    /**
     * Evaluate Symbol
     *
     * @param int   $ypos   Y position
     * @param int   $width  Width
     * @param array $frameY
     * @param array $frameYM
     *
     * @return int demerit
     */
    protected function evaluateSymbolB($ypos, $width, $frameY, $frameYM)
    {
        $head = 0;
        $demerit = 0;
        $this->runLength[0] = 1;
        for ($xpos = 0; $xpos < $width; ++$xpos) {
            if (($xpos > 0) && ($ypos > 0)) {
                $b22 = ord($frameY[$xpos])
                    & ord($frameY[($xpos - 1)])
                    & ord($frameYM[$xpos])
                    & ord($frameYM[($xpos - 1)]);
                $w22 = ord($frameY[$xpos])
                    | ord($frameY[($xpos - 1)])
                    | ord($frameYM[$xpos])
                    | ord($frameYM[($xpos - 1)]);
                if (($b22 | ($w22 ^ 1)) & 1) {
                    $demerit += Data::N2;
                }
            }
            if (($xpos == 0) && (ord($frameY[$xpos]) & 1)) {
                $this->runLength[0] = -1;
                $head = 1;
                $this->runLength[$head] = 1;
            } elseif ($xpos > 0) {
                if ((ord($frameY[$xpos]) ^ ord($frameY[($xpos - 1)])) & 1) {
                    $head++;
                    $this->runLength[$head] = 1;
                } else {
                    ++$this->runLength[$head];
                }
            }
        }
        return ($demerit + $this->calcN1N3($head + 1));
    }

    /**
     * Calc N1 N3
     *
     * @param int $length
     *
     * @return int demerit
     */
    protected function calcN1N3($length)
    {
        $demerit = 0;
        for ($idx = 0; $idx < $length; ++$idx) {
            if ($this->runLength[$idx] >= 5) {
                $demerit += (Data::N1 + ($this->runLength[$idx] - 5));
            }
            if (($idx & 1) && ($idx >= 3) && ($idx < ($length - 2)) && ($this->runLength[$idx] % 3 == 0)) {
                $demerit += $this->calcN1N3delta($length, $idx);
            }
        }
        return $demerit;
    }

    /**
     * Calc N1 N3 delta
     *
     * @param int $length
     * @param int $idx
     *
     * @return int demerit delta
     */
    protected function calcN1N3delta($length, $idx)
    {
        $fact = (int)($this->runLength[$idx] / 3);
        if (($this->runLength[($idx - 2)] == $fact)
            && ($this->runLength[($idx - 1)] == $fact)
            && ($this->runLength[($idx + 1)] == $fact)
            && ($this->runLength[($idx + 2)] == $fact)) {
            if (($this->runLength[($idx - 3)] < 0) || ($this->runLength[($idx - 3)] >= (4 * $fact))) {
                return Data::N3;
            } elseif ((($idx + 3) >= $length) || ($this->runLength[($idx + 3)] >= (4 * $fact))) {
                return Data::N3;
            }
        }
        return 0;
    }
}
MaskNum.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/MaskNum.php'
View Content
<?php
/**
 * MaskNum.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\MaskNum
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class MaskNum
{
    /**
     * Make Mask Number
     *
     * @param int  $maskNo Mask number
     * @param int  $width  Width
     * @param int  $frame  Frame
     * @param int  $mask   Mask
     *
     * @return int mask number
     */
    protected function makeMaskNo($maskNo, $width, $frame, &$mask)
    {
        $bnum = 0;
        $bitMask = $this->generateMaskNo($maskNo, $width, $frame);
        $mask = $frame;
        for ($ypos = 0; $ypos < $width; ++$ypos) {
            for ($xpos = 0; $xpos < $width; ++$xpos) {
                if ($bitMask[$ypos][$xpos] == 1) {
                    $mask[$ypos][$xpos] = chr(ord($frame[$ypos][$xpos]) ^ ((int)($bitMask[$ypos][$xpos])));
                }
                $bnum += (int)(ord($mask[$ypos][$xpos]) & 1);
            }
        }
        return $bnum;
    }

    /**
     * Return bit mask
     *
     * @param int   $maskNo Mask number
     * @param int   $width  Width
     * @param array $frame  Frame
     *
     * @return array bit mask
     */
    protected function generateMaskNo($maskNo, $width, $frame)
    {
        $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
        for ($ypos = 0; $ypos < $width; ++$ypos) {
            for ($xpos = 0; $xpos < $width; ++$xpos) {
                if (ord($frame[$ypos][$xpos]) & 0x80) {
                    $bitMask[$ypos][$xpos] = 0;
                } else {
                    $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $xpos, $ypos);
                    $bitMask[$ypos][$xpos] = (($maskFunc == 0) ? 1 : 0);
                }
            }
        }
        return $bitMask;
    }

    /**
     * Mask 0
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask0($xpos, $ypos)
    {
        return (($xpos + $ypos) & 1);
    }

    /**
     * Mask 1
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask1($xpos, $ypos)
    {
        $xpos = null;
        return ($ypos & 1);
    }

    /**
     * Mask 2
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask2($xpos, $ypos)
    {
        $ypos = null;
        return ($xpos % 3);
    }

    /**
     * Mask 3
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask3($xpos, $ypos)
    {
        return (($xpos + $ypos) % 3);
    }

    /**
     * Mask 4
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask4($xpos, $ypos)
    {
        return ((((int)($ypos / 2)) + ((int)($xpos / 3))) & 1);
    }

    /**
     * Mask 5
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask5($xpos, $ypos)
    {
        return ((($xpos * $ypos) & 1) + ($xpos * $ypos) % 3);
    }

    /**
     * Mask 6
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask6($xpos, $ypos)
    {
        return (((($xpos * $ypos) & 1) + ($xpos * $ypos) % 3) & 1);
    }

    /**
     * Mask 7
     *
     * @param int $xpos X position
     * @param int $ypos Y position
     *
     * @return int mask
     */
    protected function mask7($xpos, $ypos)
    {
        return (((($xpos * $ypos) % 3) + (($xpos + $ypos) & 1)) & 1);
    }
}
Spec.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Spec.php'
View Content
<?php
/**
 * Spec.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Spec
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
class Spec extends \Com\Tecnick\Barcode\Type\Square\QrCode\SpecRs
{
    /**
     * Replace a value on the array at the specified position
     *
     * @param array $srctab
     * @param int    $xpos       X position
     * @param int    $ypos       Y position
     * @param string $repl    Value to replace
     * @param int    $replLen Length of the repl string
     *
     * @return array srctab
     */
    public function qrstrset($srctab, $xpos, $ypos, $repl, $replLen = false)
    {
        $srctab[$ypos] = substr_replace(
            $srctab[$ypos],
            ($replLen !== false) ? substr($repl, 0, $replLen) : $repl,
            $xpos,
            ($replLen !== false) ? $replLen : strlen($repl)
        );
        return $srctab;
    }

    /**
     * Return maximum data code length (bytes) for the version.
     *
     * @param int $version Version
     * @param int $level   Error correction level
     *
     * @return int maximum size (bytes)
     */
    public function getDataLength($version, $level)
    {
        return (Data::$capacity[$version][Data::QRCAP_WORDS] - Data::$capacity[$version][Data::QRCAP_EC][$level]);
    }

    /**
     * Return maximum error correction code length (bytes) for the version.
     *
     * @param int $version Version
     * @param int $level   Error correction level
     *
     * @return int ECC size (bytes)
     */
    public function getECCLength($version, $level)
    {
        return Data::$capacity[$version][Data::QRCAP_EC][$level];
    }

    /**
     * Return the width of the symbol for the version.
     *
     * @param int $version Version
     *
     * @return int width
     */
    public function getWidth($version)
    {
        return Data::$capacity[$version][Data::QRCAP_WIDTH];
    }

    /**
     * Return the numer of remainder bits.
     *
     * @param int $version Version
     *
     * @return int number of remainder bits
     */
    public function getRemainder($version)
    {
        return Data::$capacity[$version][Data::QRCAP_REMINDER];
    }

    /**
     * Return the maximum length for the mode and version.
     *
     * @param int $mode    Encoding mode
     * @param int $version Version
     *
     * @return int the maximum length (bytes)
     */
    public function maximumWords($mode, $version)
    {
        if ($mode == Data::$encodingModes['ST']) {
            return 3;
        }
        if ($version <= 9) {
            $lval = 0;
        } elseif ($version <= 26) {
            $lval = 1;
        } else {
            $lval = 2;
        }
        $bits = Data::$lengthTableBits[$mode][$lval];
        $words = (1 << $bits) - 1;
        if ($mode == Data::$encodingModes['KJ']) {
            $words *= 2; // the number of bytes is required
        }
        return $words;
    }

    /**
     * Return an array of ECC specification.
     *
     * @param int   $version Version
     * @param int   $level   Error correction level
     * @param array $spec    Array of ECC specification contains as following:
     *                       {# of type1 blocks, # of data code, # of ecc code, # of type2 blocks, # of data code}
     *
     * @return array spec
     */
    public function getEccSpec($version, $level, $spec)
    {
        if (count($spec) < 5) {
            $spec = array(0, 0, 0, 0, 0);
        }
        $bv1 = Data::$eccTable[$version][$level][0];
        $bv2 = Data::$eccTable[$version][$level][1];
        $data = $this->getDataLength($version, $level);
        $ecc = $this->getECCLength($version, $level);
        if ($bv2 == 0) {
            $spec[0] = $bv1;
            $spec[1] = (int)($data / $bv1);
            $spec[2] = (int)($ecc / $bv1);
            $spec[3] = 0;
            $spec[4] = 0;
        } else {
            $spec[0] = $bv1;
            $spec[1] = (int)($data / ($bv1 + $bv2));
            $spec[2] = (int)($ecc  / ($bv1 + $bv2));
            $spec[3] = $bv2;
            $spec[4] = $spec[1] + 1;
        }
        return $spec;
    }

    /**
     * Put an alignment marker.
     *
     * @param array $frame Frame
     * @param int   $pox   X center coordinate of the pattern
     * @param int   $poy   Y center coordinate of the pattern
     *
     * @return array frame
     */
    public function putAlignmentMarker($frame, $pox, $poy)
    {
        $finder = array(
            "\xa1\xa1\xa1\xa1\xa1",
            "\xa1\xa0\xa0\xa0\xa1",
            "\xa1\xa0\xa1\xa0\xa1",
            "\xa1\xa0\xa0\xa0\xa1",
            "\xa1\xa1\xa1\xa1\xa1"
        );
        $yStart = $poy - 2;
        $xStart = $pox - 2;
        for ($ydx = 0; $ydx < 5; ++$ydx) {
            $frame = $this->qrstrset($frame, $xStart, ($yStart + $ydx), $finder[$ydx]);
        }
        return $frame;
    }

    /**
     * Put an alignment pattern.
     *
     * @param int   $version Version
     * @param array $frame   Frame
     * @param int   $width   Width
     *
     * @return array frame
     */
    public function putAlignmentPattern($version, $frame, $width)
    {
        if ($version < 2) {
            return $frame;
        }
        $dval = Data::$alignmentPattern[$version][1] - Data::$alignmentPattern[$version][0];
        if ($dval < 0) {
            $wdt = 2;
        } else {
            $wdt = (int)(($width - Data::$alignmentPattern[$version][0]) / $dval + 2);
        }
        if ($wdt * $wdt - 3 == 1) {
            $psx = Data::$alignmentPattern[$version][0];
            $psy = Data::$alignmentPattern[$version][0];
            $frame = $this->putAlignmentMarker($frame, $psx, $psy);
            return $frame;
        }
        $cpx = Data::$alignmentPattern[$version][0];
        $wdo = $wdt - 1;
        for ($xpos = 1; $xpos < $wdo; ++$xpos) {
            $frame = $this->putAlignmentMarker($frame, 6, $cpx);
            $frame = $this->putAlignmentMarker($frame, $cpx, 6);
            $cpx += $dval;
        }
        $cpy = Data::$alignmentPattern[$version][0];
        for ($y=0; $y < $wdo; ++$y) {
            $cpx = Data::$alignmentPattern[$version][0];
            for ($xpos = 0; $xpos < $wdo; ++$xpos) {
                $frame = $this->putAlignmentMarker($frame, $cpx, $cpy);
                $cpx += $dval;
            }
            $cpy += $dval;
        }
        return $frame;
    }

    /**
     * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater.
     * Use lower 18 bits.
     *
     * @param int $version Version
     *
     * @return BCH encoded version information pattern
     */
    public function getVersionPattern($version)
    {
        if (($version < 7) || ($version > Data::QRSPEC_VERSION_MAX)) {
            return 0;
        }
        return Data::$versionPattern[($version - 7)];
    }

    /**
     * Return BCH encoded format information pattern.
     *
     * @param array $maskNo Mask number
     * @param int   $level  Error correction level
     *
     * @return BCH encoded format information pattern
     */
    public function getFormatInfo($maskNo, $level)
    {
        if (($maskNo < 0)
            || ($maskNo > 7)
            || ($level < 0)
            || ($level > 3)
        ) {
            return 0;
        }
        return Data::$formatInfo[$level][$maskNo];
    }

    /**
     * Put a finder pattern.
     *
     * @param array $frame Frame
     * @param int   $pox   X center coordinate of the pattern
     * @param int   $poy   Y center coordinate of the pattern
     *
     * @return array frame
     */
    public function putFinderPattern($frame, $pox, $poy)
    {
        $finder = array(
            "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
            "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
            "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
            "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
            "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
            "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
            "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
        );
        for ($ypos = 0; $ypos < 7; ++$ypos) {
            $frame = $this->qrstrset($frame, $pox, ($poy + $ypos), $finder[$ypos]);
        }
        return $frame;
    }
}
SpecRs.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/SpecRs.php'
View Content
<?php
/**
 * SpecRs.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\SpecRs
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
abstract class SpecRs
{
    /**
     * Return block number 0
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsBlockNum($spec)
    {
        return ($spec[0] + $spec[3]);
    }

    /**
     * Return block number 1
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsBlockNum1($spec)
    {
        return $spec[0];
    }

    /**
     * Return data codes 1
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsDataCodes1($spec)
    {
        return $spec[1];
    }

    /**
     * Return ecc codes 1
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsEccCodes1($spec)
    {
        return $spec[2];
    }

    /**
     * Return block number 2
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsBlockNum2($spec)
    {
        return $spec[3];
    }

    /**
     * Return data codes 2
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsDataCodes2($spec)
    {
        return $spec[4];
    }

    /**
     * Return ecc codes 2
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsEccCodes2($spec)
    {
        return $spec[2];
    }

    /**
     * Return data length
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsDataLength($spec)
    {
        return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
    }

    /**
     * Return ecc length
     *
     * @param array $spec
     *
     * @return int value
     */
    public function rsEccLength($spec)
    {
        return ($spec[0] + $spec[3]) * $spec[2];
    }

    /**
     * Return a copy of initialized frame.
     *
     * @param int $version Version
     *
     * @return Array of unsigned char.
     */
    public function createFrame($version)
    {
        $width = Data::$capacity[$version][Data::QRCAP_WIDTH];
        $frameLine = str_repeat("\0", $width);
        $frame = array_fill(0, $width, $frameLine);
        // Finder pattern
        $frame = $this->putFinderPattern($frame, 0, 0);
        $frame = $this->putFinderPattern($frame, $width - 7, 0);
        $frame = $this->putFinderPattern($frame, 0, $width - 7);
        // Separator
        $yOffset = $width - 7;
        for ($ypos = 0; $ypos < 7; ++$ypos) {
            $frame[$ypos][7] = "\xc0";
            $frame[$ypos][$width - 8] = "\xc0";
            $frame[$yOffset][7] = "\xc0";
            ++$yOffset;
        }
        $setPattern = str_repeat("\xc0", 8);
        $frame = $this->qrstrset($frame, 0, 7, $setPattern);
        $frame = $this->qrstrset($frame, $width-8, 7, $setPattern);
        $frame = $this->qrstrset($frame, 0, $width - 8, $setPattern);
        // Format info
        $setPattern = str_repeat("\x84", 9);
        $frame = $this->qrstrset($frame, 0, 8, $setPattern);
        $frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8);
        $yOffset = $width - 8;
        for ($ypos = 0; $ypos < 8; ++$ypos, ++$yOffset) {
            $frame[$ypos][8] = "\x84";
            $frame[$yOffset][8] = "\x84";
        }
        // Timing pattern
        $wdo = $width - 15;
        for ($idx = 1; $idx < $wdo; ++$idx) {
            $frame[6][(7 + $idx)] = chr(0x90 | ($idx & 1));
            $frame[(7 + $idx)][6] = chr(0x90 | ($idx & 1));
        }
        // Alignment pattern
        $frame = $this->putAlignmentPattern($version, $frame, $width);
        // Version information
        if ($version >= 7) {
            $vinf = $this->getVersionPattern($version);
            $val = $vinf;
            for ($xpos = 0; $xpos < 6; ++$xpos) {
                for ($ypos = 0; $ypos < 3; ++$ypos) {
                    $frame[(($width - 11) + $ypos)][$xpos] = chr(0x88 | ($val & 1));
                    $val = $val >> 1;
                }
            }
            $val = $vinf;
            for ($ypos = 0; $ypos < 6; ++$ypos) {
                for ($xpos = 0; $xpos < 3; ++$xpos) {
                    $frame[$ypos][($xpos + ($width - 11))] = chr(0x88 | ($val & 1));
                    $val = $val >> 1;
                }
            }
        }
        // and a little bit...
        $frame[$width - 8][8] = "\x81";
        return $frame;
    }
}
Split.php
wget 'https://lists2.roe3.org/hesk/inc/tecnick/Barcode/Type/Square/QrCode/Split.php'
View Content
<?php
/**
 * Split.php
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 *
 * This file is part of tc-lib-barcode software library.
 */

namespace Com\Tecnick\Barcode\Type\Square\QrCode;

use \Com\Tecnick\Barcode\Exception as BarcodeException;
use \Com\Tecnick\Barcode\Type\Square\QrCode\Data;
use \Com\Tecnick\Barcode\Type\Square\QrCode\ByteStream;

/**
 * Com\Tecnick\Barcode\Type\Square\QrCode\Split
 *
 * @since       2015-02-21
 * @category    Library
 * @package     Barcode
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2010-2016 Nicola Asuni - Tecnick.com LTD
 * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 * @link        https://github.com/tecnickcom/tc-lib-barcode
 */
class Split
{
    /**
     * EncodingMode class object
     *
     * @var \Com\Tecnick\Barcode\Type\Square\QrCode\EncodingMode
     */
    protected $bsObj;

    /**
     * Input items
     *
     * @var array
     */
    protected $items = array();

    /**
     * QR code version.
     * The Size of QRcode is defined as version. Version is an integer value from 1 to 40.
     * Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
     * So version 40 is 177*177 matrix.
     *
     * @var int
     */
    protected $version = 0;

    /**
     * Encoding mode
     *
     * @var int
     */
    protected $hint = 2;

    /**
     * Initialize
     *
     * @param ByteStream   $bsObj   ByteStream Class object
     * @param int          $hint    Encoding mode
     * @param int          $version Code version
     */
    public function __construct($bsObj, $hint, $version)
    {
        $this->bsObj = $bsObj;
        $this->items = array();
        $this->hint = $hint;
        $this->version = $version;
    }

    /**
     * Split the input string
     *
     * @param string $data Data
     *
     * @return array items
     */
    public function getSplittedString($data)
    {
        while (strlen($data) > 0) {
            $mode = $this->bsObj->getEncodingMode($data, 0);
            switch ($mode) {
                case Data::$encodingModes['NM']:
                    $length = $this->eatNum($data);
                    break;
                case Data::$encodingModes['AN']:
                    $length = $this->eatAn($data);
                    break;
                case Data::$encodingModes['KJ']:
                    if ($this->hint == Data::$encodingModes['KJ']) {
                        $length = $this->eatKanji($data);
                    } else {
                        $length = $this->eat8($data);
                    }
                    break;
                default:
                    $length = $this->eat8($data);
                    break;
            }
            if ($length == 0) {
                break;
            }
            if ($length < 0) {
                throw new BarcodeException('Error while splitting the input data');
            }
            $data = substr($data, $length);
        }
        return $this->items;
    }

    /**
     * eatNum
     *
     * @param string $data Data
     *
     * @return int run
     */
    protected function eatNum($data)
    {
        $lng = $this->bsObj->getLengthIndicator(Data::$encodingModes['NM']);
        $pos = 0;
        while ($this->bsObj->isDigitAt($data, $pos)) {
            $pos++;
        }
        $mode = $this->bsObj->getEncodingMode($data, $pos);
        if ($mode == Data::$encodingModes['8B']) {
            $dif = $this->bsObj->estimateBitsModeNum($pos) + 4 + $lng
                + $this->bsObj->estimateBitsMode8(1)         // + 4 + l8
                - $this->bsObj->estimateBitsMode8($pos + 1); // - 4 - l8
            if ($dif > 0) {
                return $this->eat8($data);
            }
        }
        if ($mode == Data::$encodingModes['AN']) {
            $dif = $this->bsObj->estimateBitsModeNum($pos) + 4 + $lng
                + $this->bsObj->estimateBitsModeAn(1)        // + 4 + la
                - $this->bsObj->estimateBitsModeAn($pos + 1);// - 4 - la
            if ($dif > 0) {
                return $this->eatAn($data);
            }
        }
        $this->items = $this->bsObj->appendNewInputItem(
            $this->items,
            Data::$encodingModes['NM'],
            $pos,
            str_split($data)
        );
        return $pos;
    }

    /**
     * eatAn
     *
     * @param string $data Data
     * @return int run
     */
    protected function eatAn($data)
    {
        $lag = $this->bsObj->getLengthIndicator(Data::$encodingModes['AN']);
        $lng = $this->bsObj->getLengthIndicator(Data::$encodingModes['NM']);
        $pos =1 ;
        while ($this->bsObj->isAlphanumericAt($data, $pos)) {
            if ($this->bsObj->isDigitAt($data, $pos)) {
                $qix = $pos;
                while ($this->bsObj->isDigitAt($data, $qix)) {
                    $qix++;
                }
                $dif = $this->bsObj->estimateBitsModeAn($pos) // + 4 + lag
                    + $this->bsObj->estimateBitsModeNum($qix - $pos) + 4 + $lng
                    - $this->bsObj->estimateBitsModeAn($qix); // - 4 - la
                if ($dif < 0) {
                    break;
                } else {
                    $pos = $qix;
                }
            } else {
                $pos++;
            }
        }
        if (!$this->bsObj->isAlphanumericAt($data, $pos)) {
            $dif = $this->bsObj->estimateBitsModeAn($pos) + 4 + $lag
                + $this->bsObj->estimateBitsMode8(1) // + 4 + l8
                - $this->bsObj->estimateBitsMode8($pos + 1); // - 4 - l8
            if ($dif > 0) {
                return $this->eat8($data);
            }
        }
        $this->items = $this->bsObj->appendNewInputItem(
            $this->items,
            Data::$encodingModes['AN'],
            $pos,
            str_split($data)
        );
        return $pos;
    }

    /**
     * eatKanji
     *
     * @param string $data Data
     * @return int run
     */
    protected function eatKanji($data)
    {
        $pos = 0;
        while ($this->bsObj->getEncodingMode($data, $pos) == Data::$encodingModes['KJ']) {
            $pos += 2;
        }
        $this->items = $this->bsObj->appendNewInputItem(
            $this->items,
            Data::$encodingModes['KJ'],
            $pos,
            str_split($data)
        );
        return $pos;
    }

    /**
     * eat8
     *
     * @param string $data Data
     * @return int run
     */
    protected function eat8($data)
    {
        $lag = $this->bsObj->getLengthIndicator(Data::$encodingModes['AN']);
        $lng = $this->bsObj->getLengthIndicator(Data::$encodingModes['NM']);
        $pos = 1;
        $dataStrLen = strlen($data);
        while ($pos < $dataStrLen) {
            $mode = $this->bsObj->getEncodingMode($data, $pos);
            if ($mode == Data::$encodingModes['KJ']) {
                break;
            }
            if ($mode == Data::$encodingModes['NM']) {
                $qix = $pos;
                while ($this->bsObj->isDigitAt($data, $qix)) {
                    $qix++;
                }
                $dif = $this->bsObj->estimateBitsMode8($pos) // + 4 + l8
                    + $this->bsObj->estimateBitsModeNum($qix - $pos) + 4 + $lng
                    - $this->bsObj->estimateBitsMode8($qix); // - 4 - l8
                if ($dif < 0) {
                    break;
                } else {
                    $pos = $qix;
                }
            } elseif ($mode == Data::$encodingModes['AN']) {
                $qix = $pos;
                while ($this->bsObj->isAlphanumericAt($data, $qix)) {
                    $qix++;
                }
                $dif = $this->bsObj->estimateBitsMode8($pos)  // + 4 + l8
                    + $this->bsObj->estimateBitsModeAn($qix - $pos) + 4 + $lag
                    - $this->bsObj->estimateBitsMode8($qix); // - 4 - l8
                if ($dif < 0) {
                    break;
                } else {
                    $pos = $qix;
                }
            } else {
                $pos++;
            }
        }
        $this->items = $this->bsObj->appendNewInputItem(
            $this->items,
            Data::$encodingModes['8B'],
            $pos,
            str_split($data)
        );
        return $pos;
    }
}