利用到一个qrcode类 比较简洁 原作者没有加入二维码嵌入logo的功能 在这里我进行了小小的修改 可以实现生成微信支付二维码时打上logo 生成png格式的利用到该类中的png方法(我已经改好了) 生成png格式的利用到该类中的jpg方法(仿照png方法里的内容自行修改)

<?php
namespace Home\Vendor;

class Qrcode {
    
    private $QR_MODE_NL = -1;
    private $QR_MODE_NM = 0;
    private $QR_MODE_AN = 1;
    private $QR_MODE_8B = 2;
    private $QR_MODE_KJ = 3;
    private $QR_MODE_ST = 4;
    
    private $QR_ECLEVEL_L = 0;
    private $QR_ECLEVEL_M = 1;
    private $QR_ECLEVEL_Q = 2;
    private $QR_ECLEVEL_H = 3;
    
    private $QRSPEC_VERSION_MAX = 40;
    private $QRSPEC_WIDTH_MAX = 177;
    private $QRCAP_WIDTH = 0;
    private $QRCAP_WORDS = 1;
    private $QRCAP_REMINDER = 2;
    private $QRCAP_EC = 3;
    private $STRUCTURE_HEADER_BITS = 20;
    private $MAX_STRUCTURED_SYMBOLS = 16;
    
    
    private $N1 = 3;
    private $N2 = 3;
    private $N3 = 40;
    private $N4 = 10;
    
    private $QR_FIND_BEST_MASK = true;
    private $QR_FIND_FROM_RANDOM  = 2;
    private $QR_DEFAULT_MASK = 2;
    
    /**
     * @var barcode array to be returned which is readable by TCPDF
     * @access protected
     */
    protected $barcode_array = array();

    /**
     * @var QR code version. Size of QRcode is defined as version. Version is 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.
     * @access protected
     */
    protected $version = 0;

    /**
     * @var Levels of error correction. See definitions for possible values.
     * @access protected
     */
    protected $level = 0;

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

    /**
     * @var if true the input string will be converted to uppercase
     * @access protected
     */
    protected $casesensitive = true;

    /**
     * @var structured QR code (not supported yet)
     * @access protected
     */
    protected $structured = 0;

    /**
     * @var mask data
     * @access protected
     */
    protected $data;

    // FrameFiller

    /**
     * @var width
     * @access protected
     */
    protected $width;

    /**
     * @var frame
     * @access protected
     */
    protected $frame;

    /**
     * @var X position of bit
     * @access protected
     */
    protected $x;

    /**
     * @var Y position of bit
     * @access protected
     */
    protected $y;

    /**
     * @var direction
     * @access protected
     */
    protected $dir;

    /**
     * @var single bit
     * @access protected
     */
    protected $bit;

    // ---- QRrawcode ----

    /**
     * @var data code
     * @access protected
     */
    protected $datacode = array();

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

    /**
     * @var blocks
     * @access protected
     */
    protected $blocks;

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

    /**
     * @var counter
     * @access protected
     */
    protected $count;

    /**
     * @var data length
     * @access protected
     */
    protected $dataLength;

    /**
     * @var error correction length
     * @access protected
     */
    protected $eccLength;

    /**
     * @var b1
     * @access protected
     */
    protected $b1;

    // ---- QRmask ----

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

    // ---- QRsplit ----

    /**
     * @var input data string
     * @access protected
     */
    protected $dataStr = '';

    /**
     * @var input items
     * @access protected
     */
    protected $items;

    // Reed-Solomon items

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

    /**
     * @var array of frames
     * @access protected
     */
    protected $frames = array();

    /**
     * @var alphabet-numeric convesion table
     * @access protected
     */
    protected $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  //
        );

    /**
     * @var array Table of the capacity of symbols
     * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
     * @access protected
     */
    protected $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
    );

    /**
     * @var array Length indicator
     * @access protected
     */
    protected $lengthTableBits = array(
        array(10, 12, 14),
        array( 9, 11, 13),
        array( 8, 16, 16),
        array( 8, 10, 12)
    );

    /**
     * @var array Table of the error correction code (Reed-Solomon block)
     * See Table 12-16 (pp.30-36), JIS X0510:2004.
     * @access protected
     */
    protected $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
    );

    /**
     * @var 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.
     * @access protected
     */
    protected $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
    );

    /**
     * @var array Version information pattern (BCH coded).
     * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
     * size: [QRSPEC_VERSION_MAX - 6]
     * @access protected
     */
    protected $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
    );

    /**
     * @var array Format information
     * @access protected
     */
    protected $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)  //
    );

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

    
    public function __construct()
    {
        $hint = $this->QR_MODE_8B;
        
        $level = $this->QR_ECLEVEL_L;
        
    }
    /**
     * This is the class constructor.
     * Creates a QRcode object
     * @param string $code code to represent using QRcode
     * @param string $eclevel error level: <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
     * @access public
     * @since 1.0.000
     */
    private function set($code, $eclevel = 'H') {
        $barcode_array = array();
        if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
            return false;
        }
        // set error correction level
        $this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
        if ($this->level === false) {
            $this->level = $this->QR_ECLEVEL_H;
        }
        if (($this->hint != $this->QR_MODE_8B) AND ($this->hint != $this->QR_MODE_KJ)) {
            return false;
        }
        if (($this->version < 0) OR ($this->version > $this->QRSPEC_VERSION_MAX)) {
            return false;
        }
        $this->items = array();
        $this->encodeString($code);
        $qrTab = $this->binarize($this->data);
        $size = count($qrTab);
        $barcode_array['num_rows'] = $size;
        $barcode_array['num_cols'] = $size;
        $barcode_array['bcode'] = array();
        foreach ($qrTab as $line) {
            $arrAdd = array();
            foreach (str_split($line) as $char) {
                $arrAdd[] = ($char=='1')?1:0;
            }
            $barcode_array['bcode'][] = $arrAdd;
        }
        $this->barcode_array = $barcode_array;
    }

    /**
     * Returns a barcode array which is readable by TCPDF
     * @return array barcode array readable by TCPDF;
     * @access public
     */
    private function getBarcodeArray() {
        return $this->barcode_array;
    }
    
    
    

    /**
     * Convert the frame in binary form
     * @param array $frame array to binarize
     * @return array frame in binary form
     */
    protected function binarize($frame) {
        $len = count($frame);
        // the frame is square (width = height)
        foreach ($frame as &$frameLine) {
            for ($i=0; $i<$len; $i++) {
                $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
            }
        }
        return $frame;
    }

    /**
     * Encode the input string to QR code
     * @param string $string input string to encode
     */
    protected function encodeString($string) {
        $this->dataStr = $string;
        if (!$this->casesensitive) {
            $this->toUpper();
        }
        $ret = $this->splitString();
        if ($ret < 0) {
            return NULL;
        }
        $this->encodeMask(-1);
    }

    /**
     * Encode mask
     * @param int $mask masking mode
     */
    protected function encodeMask($mask) {
        $spec = array(0, 0, 0, 0, 0);
        $this->datacode = $this->getByteStream($this->items);
        if (is_null($this->datacode)) {
            return NULL;
        }
        $spec = $this->getEccSpec($this->version, $this->level, $spec);
        $this->b1 = $this->rsBlockNum1($spec);
        $this->dataLength = $this->rsDataLength($spec);
        $this->eccLength = $this->rsEccLength($spec);
        $this->ecccode = array_fill(0, $this->eccLength, 0);
        $this->blocks = $this->rsBlockNum($spec);
        $ret = $this->init($spec);
        if ($ret < 0) {
            return NULL;
        }
        $this->count = 0;
        $this->width = $this->getWidth($this->version);
        $this->frame = $this->newFrame($this->version);
        $this->x = $this->width - 1;
        $this->y = $this->width - 1;
        $this->dir = -1;
        $this->bit = -1;
        // inteleaved data and ecc codes
        for ($i=0; $i < ($this->dataLength + $this->eccLength); $i++) {
            $code = $this->getCode();
            $bit = 0x80;
            for ($j=0; $j<8; $j++) {
                $addr = $this->getNextPosition();
                $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
                $bit = $bit >> 1;
            }
        }
        // remainder bits
        $j = $this->getRemainder($this->version);
        for ($i=0; $i<$j; $i++) {
            $addr = $this->getNextPosition();
            $this->setFrameAt($addr, 0x02);
        }
        // masking
        $this->runLength = array_fill(0, $this->QRSPEC_WIDTH_MAX + 1, 0);
        if ($mask < 0) {
            if ($this->QR_FIND_BEST_MASK) {
                $masked = $this->mask($this->width, $this->frame, $this->level);
            } else {
                $masked = $this->makeMask($this->width, $this->frame, (intval($this->QR_DEFAULT_MASK) % 8), $this->level);
            }
        } else {
            $masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
        }
        if ($masked == NULL) {
            return NULL;
        }
        $this->data = $masked;
    }

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

    // FrameFiller

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

    /**
     * Get frame value at specified position
     * @param array $at x,y position
     * @return value at specified position
     */
    protected function getFrameAt($at) {
        return ord($this->frame[$at['y']][$at['x']]);
    }

    /**
     * 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->x, 'y'=>$this->y);
            }
            $x = $this->x;
            $y = $this->y;
            $w = $this->width;
            if ($this->bit == 0) {
                $x--;
                $this->bit++;
            } else {
                $x++;
                $y += $this->dir;
                $this->bit--;
            }
            if ($this->dir < 0) {
                if ($y < 0) {
                    $y = 0;
                    $x -= 2;
                    $this->dir = 1;
                    if ($x == 6) {
                        $x--;
                        $y = 9;
                    }
                }
            } else {
                if ($y == $w) {
                    $y = $w - 1;
                    $x -= 2;
                    $this->dir = -1;
                    if ($x == 6) {
                        $x--;
                        $y -= 8;
                    }
                }
            }
            if (($x < 0) OR ($y < 0)) {
                return NULL;
            }
            $this->x = $x;
            $this->y = $y;
        } while(ord($this->frame[$y][$x]) & 0x80);
        return array('x'=>$x, 'y'=>$y);
    }

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

    // QRrawcode

    /**
     * Initialize code.
     * @param array $spec array of ECC specification
     * @return 0 in case of success, -1 in case of error
     */
    protected function init($spec) {
        $dl = $this->rsDataCodes1($spec);
        $el = $this->rsEccCodes1($spec);
        $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
        $blockNo = 0;
        $dataPos = 0;
        $eccPos = 0;
        $endfor = $this->rsBlockNum1($spec);
        for ($i=0; $i < $endfor; ++$i) {
            $ecc = array_slice($this->ecccode, $eccPos);
            $this->rsblocks[$blockNo] = array();
            $this->rsblocks[$blockNo]['dataLength'] = $dl;
            $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
            $this->rsblocks[$blockNo]['eccLength'] = $el;
            $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
            $this->rsblocks[$blockNo]['ecc'] = $ecc;
            $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
            $dataPos += $dl;
            $eccPos += $el;
            $blockNo++;
        }
        if ($this->rsBlockNum2($spec) == 0) {
            return 0;
        }
        $dl = $this->rsDataCodes2($spec);
        $el = $this->rsEccCodes2($spec);
        $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
        if ($rs == NULL) {
            return -1;
        }
        $endfor = $this->rsBlockNum2($spec);
        for ($i=0; $i < $endfor; ++$i) {
            $ecc = array_slice($this->ecccode, $eccPos);
            $this->rsblocks[$blockNo] = array();
            $this->rsblocks[$blockNo]['dataLength'] = $dl;
            $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
            $this->rsblocks[$blockNo]['eccLength'] = $el;
            $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
            $this->rsblocks[$blockNo]['ecc'] = $ecc;
            $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
            $dataPos += $dl;
            $eccPos += $el;
            $blockNo++;
        }
        return 0;
    }

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

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

    // QRmask

    /**
     * Write Format Information on frame and returns the number of black bits
     * @param int $width frame width
     * @param array $frame frame
     * @param array $mask masking mode
     * @param int $level error correction level
     * @return int blacks
     */
     protected function writeFormatInformation($width, &$frame, $mask, $level) {
        $blacks = 0;
        $format =  $this->getFormatInfo($mask, $level);
        for ($i=0; $i<8; ++$i) {
            if ($format & 1) {
                $blacks += 2;
                $v = 0x85;
            } else {
                $v = 0x84;
            }
            $frame[8][$width - 1 - $i] = chr($v);
            if ($i < 6) {
                $frame[$i][8] = chr($v);
            } else {
                $frame[$i + 1][8] = chr($v);
            }
            $format = $format >> 1;
        }
        for ($i=0; $i<7; ++$i) {
        if ($format & 1) {
            $blacks += 2;
            $v = 0x85;
        } else {
            $v = 0x84;
        }
        $frame[$width - 7 + $i][8] = chr($v);
        if ($i == 0) {
            $frame[8][7] = chr($v);
        } else {
            $frame[8][6 - $i] = chr($v);
        }
        $format = $format >> 1;
        }
        return $blacks;
    }

    /**
     * mask0
     * @param int $x X position
     * @param int $y Y position
     * @return int mask
     */
     protected function mask0($x, $y) {
        return ($x + $y) & 1;
    }

    /**
     * mask1
     * @param int $x X position
     * @param int $y Y position
     * @return int mask
     */
     protected function mask1($x, $y) {
        return ($y & 1);
    }

    /**
     * mask2
     * @param int $x X position
     * @param int $y Y position
     * @return int mask
     */
     protected function mask2($x, $y) {
        return ($x % 3);
    }

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

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

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

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

    /**
     * mask7
     * @param int $x X position
     * @param int $y Y position
     * @return int mask
     */
     protected function mask7($x, $y) {
        return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
    }

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

    /**
     * makeMaskNo
     * @param int $maskNo
     * @param int $width
     * @param int $s
     * @param int $d
     * @param boolean $maskGenOnly
     * @return int b
     */
     protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
        $b = 0;
        $bitMask = array();
        $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
        if ($maskGenOnly) {
            return;
        }
        $d = $s;
        for ($y=0; $y<$width; ++$y) {
            for ($x=0; $x<$width; ++$x) {
                if ($bitMask[$y][$x] == 1) {
                    $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
                }
                $b += (int)(ord($d[$y][$x]) & 1);
            }
        }
        return $b;
    }

    /**
     * makeMask
     * @param int $width
     * @param array $frame
     * @param int $maskNo
     * @param int $level
     * @return array mask
     */
     protected function makeMask($width, $frame, $maskNo, $level) {
        $masked = array_fill(0, $width, str_repeat("\0", $width));
        $this->makeMaskNo($maskNo, $width, $frame, $masked);
        $this->writeFormatInformation($width, $masked, $maskNo, $level);
        return $masked;
    }

    /**
     * calcN1N3
     * @param int $length
     * @return int demerit
     */
     protected function calcN1N3($length) {
        $demerit = 0;
        for ($i=0; $i<$length; ++$i) {
            if ($this->runLength[$i] >= 5) {
                $demerit += ($this->N1 + ($this->runLength[$i] - 5));
            }
            if ($i & 1) {
                if (($i >= 3) AND ($i < ($length-2)) AND ($this->runLength[$i] % 3 == 0)) {
                    $fact = (int)($this->runLength[$i] / 3);
                    if (($this->runLength[$i-2] == $fact)
                        AND ($this->runLength[$i-1] == $fact)
                        AND ($this->runLength[$i+1] == $fact)
                        AND ($this->runLength[$i+2] == $fact)) {
                        if (($this->runLength[$i-3] < 0) OR ($this->runLength[$i-3] >= (4 * $fact))) {
                            $demerit += $this->N3;
                        } elseif ((($i+3) >= $length) OR ($this->runLength[$i+3] >= (4 * $fact))) {
                            $demerit += $this->N3;
                        }
                    }
                }
            }
        }
        return $demerit;
    }

    /**
     * evaluateSymbol
     * @param int $width
     * @param array $frame
     * @return int demerit
     */
     protected function evaluateSymbol($width, $frame) {
        $head = 0;
        $demerit = 0;
        for ($y=0; $y<$width; ++$y) {
            $head = 0;
            $this->runLength[0] = 1;
            $frameY = $frame[$y];
            if ($y > 0) {
                $frameYM = $frame[$y-1];
            }
            for ($x=0; $x<$width; ++$x) {
                if (($x > 0) AND ($y > 0)) {
                    $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
                    $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
                    if (($b22 | ($w22 ^ 1)) & 1) {
                        $demerit += $this->N2;
                    }
                }
                if (($x == 0) AND (ord($frameY[$x]) & 1)) {
                    $this->runLength[0] = -1;
                    $head = 1;
                    $this->runLength[$head] = 1;
                } elseif ($x > 0) {
                    if ((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
                        $head++;
                        $this->runLength[$head] = 1;
                    } else {
                        $this->runLength[$head]++;
                    }
                }
            }
            $demerit += $this->calcN1N3($head+1);
        }
        for ($x=0; $x<$width; ++$x) {
            $head = 0;
            $this->runLength[0] = 1;
            for ($y=0; $y<$width; ++$y) {
                if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
                    $this->runLength[0] = -1;
                    $head = 1;
                    $this->runLength[$head] = 1;
                } elseif ($y > 0) {
                    if ((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
                        $head++;
                        $this->runLength[$head] = 1;
                    } else {
                        $this->runLength[$head]++;
                    }
                }
            }
            $demerit += $this->calcN1N3($head+1);
        }
        return $demerit;
    }

    /**
     * mask
     * @param int $width
     * @param array $frame
     * @param int $level
     * @return array best mask
     */
     protected function mask($width, $frame, $level) {
        $minDemerit = PHP_INT_MAX;
        $bestMaskNum = 0;
        $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 ($i = 0; $i <  $howManuOut; ++$i) {
                $remPos = rand (0, count($checked_masks)-1);
                unset($checked_masks[$remPos]);
                $checked_masks = array_values($checked_masks);
            }
        }
        $bestMask = $frame;
        foreach ($checked_masks as $i) {
            $mask = array_fill(0, $width, str_repeat("\0", $width));
            $demerit = 0;
            $blacks = 0;
            $blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
            $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
            $blacks  = (int)(100 * $blacks / ($width * $width));
            $demerit = (int)((int)(abs($blacks - 50) / 5) * $this->N4);
            $demerit += $this->evaluateSymbol($width, $mask);
            if ($demerit < $minDemerit) {
                $minDemerit = $demerit;
                $bestMask = $mask;
                $bestMaskNum = $i;
            }
        }
        return $bestMask;
    }

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

    // QRsplit

    /**
     * Return true if the character at specified position is a number
     * @param string $str string
     * @param int $pos characted position
     * @return boolean true of false
     */
     protected function isdigitat($str, $pos) {
        if ($pos >= strlen($str)) {
            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 string
     * @param int $pos characted position
     * @return boolean true of false
     */
     protected function isalnumat($str, $pos) {
        if ($pos >= strlen($str)) {
            return false;
        }
        return ($this->lookAnTable(ord($str[$pos])) >= 0);
    }

    /**
     * identifyMode
     * @param int $pos
     * @return int mode
     */
     protected function identifyMode($pos) {
        if ($pos >= strlen($this->dataStr)) {
            return $this->QR_MODE_NL;
        }
        $c = $this->dataStr[$pos];
        if ($this->isdigitat($this->dataStr, $pos)) {
            return $this->QR_MODE_NM;
        } elseif ($this->isalnumat($this->dataStr, $pos)) {
            return $this->QR_MODE_AN;
        } elseif ($this->hint == $this->QR_MODE_KJ) {
            if ($pos+1 < strlen($this->dataStr)) {
                $d = $this->dataStr[$pos+1];
                $word = (ord($c) << 8) | ord($d);
                if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
                    return $this->QR_MODE_KJ;
                }
            }
        }
        return $this->QR_MODE_8B;
    }

    /**
     * eatNum
     * @return int run
     */
     protected function eatNum() {
        $ln = $this->lengthIndicator($this->QR_MODE_NM, $this->version);
        $p = 0;
        while($this->isdigitat($this->dataStr, $p)) {
            $p++;
        }
        $run = $p;
        $mode = $this->identifyMode($p);
        if ($mode == $this->QR_MODE_8B) {
            $dif = $this->estimateBitsModeNum($run) + 4 + $ln
            + $this->estimateBitsMode8(1)         // + 4 + l8
            - $this->estimateBitsMode8($run + 1); // - 4 - l8
            if ($dif > 0) {
                return $this->eat8();
            }
        }
        if ($mode == $this->QR_MODE_AN) {
            $dif = $this->estimateBitsModeNum($run) + 4 + $ln
            + $this->estimateBitsModeAn(1)        // + 4 + la
            - $this->estimateBitsModeAn($run + 1);// - 4 - la
            if ($dif > 0) {
                return $this->eatAn();
            }
        }
        $this->items = $this->appendNewInputItem($this->items, $this->QR_MODE_NM, $run, str_split($this->dataStr));
        return $run;
    }

    /**
     * eatAn
     * @return int run
     */
     protected function eatAn() {
        $la = $this->lengthIndicator($this->QR_MODE_AN,  $this->version);
        $ln = $this->lengthIndicator($this->QR_MODE_NM, $this->version);
        $p = 0;
        while($this->isalnumat($this->dataStr, $p)) {
            if ($this->isdigitat($this->dataStr, $p)) {
                $q = $p;
                while($this->isdigitat($this->dataStr, $q)) {
                    $q++;
                }
                $dif = $this->estimateBitsModeAn($p) // + 4 + la
                + $this->estimateBitsModeNum($q - $p) + 4 + $ln
                - $this->estimateBitsModeAn($q); // - 4 - la
                if ($dif < 0) {
                    break;
                } else {
                    $p = $q;
                }
            } else {
                $p++;
            }
        }
        $run = $p;
        if (!$this->isalnumat($this->dataStr, $p)) {
            $dif = $this->estimateBitsModeAn($run) + 4 + $la
            + $this->estimateBitsMode8(1) // + 4 + l8
            - $this->estimateBitsMode8($run + 1); // - 4 - l8
            if ($dif > 0) {
                return $this->eat8();
            }
        }
        $this->items = $this->appendNewInputItem($this->items, $this->QR_MODE_AN, $run, str_split($this->dataStr));
        return $run;
    }

    /**
     * eatKanji
     * @return int run
     */
     protected function eatKanji() {
        $p = 0;
        while($this->identifyMode($p) == $this->QR_MODE_KJ) {
            $p += 2;
        }
        $this->items = $this->appendNewInputItem($this->items, $this->QR_MODE_KJ, $p, str_split($this->dataStr));
        return $run;
    }

    /**
     * eat8
     * @return int run
     */
     protected function eat8() {
        $la = $this->lengthIndicator($this->QR_MODE_AN, $this->version);
        $ln = $this->lengthIndicator($this->QR_MODE_NM, $this->version);
        $p = 1;
        $dataStrLen = strlen($this->dataStr);
        while($p < $dataStrLen) {
            $mode = $this->identifyMode($p);
            if ($mode == $this->QR_MODE_KJ) {
                break;
            }
            if ($mode == $this->QR_MODE_NM) {
                $q = $p;
                while($this->isdigitat($this->dataStr, $q)) {
                    $q++;
                }
                $dif = $this->estimateBitsMode8($p) // + 4 + l8
                + $this->estimateBitsModeNum($q - $p) + 4 + $ln
                - $this->estimateBitsMode8($q); // - 4 - l8
                if ($dif < 0) {
                    break;
                } else {
                    $p = $q;
                }
            } elseif ($mode == $this->QR_MODE_AN) {
                $q = $p;
                while($this->isalnumat($this->dataStr, $q)) {
                    $q++;
                }
                $dif = $this->estimateBitsMode8($p)  // + 4 + l8
                + $this->estimateBitsModeAn($q - $p) + 4 + $la
                - $this->estimateBitsMode8($q); // - 4 - l8
                if ($dif < 0) {
                    break;
                } else {
                    $p = $q;
                }
            } else {
                $p++;
            }
        }
        $run = $p;
        $this->items = $this->appendNewInputItem($this->items, $this->QR_MODE_8B, $run, str_split($this->dataStr));
        return $run;
    }

    /**
     * splitString
     */
     protected function splitString() {
        while (strlen($this->dataStr) > 0) {
            if ($this->dataStr == '') {
                return 0;
            }
            $mode = $this->identifyMode(0);
            switch ($mode) {
                case $this->QR_MODE_NM: {
                    $length = $this->eatNum();
                    break;
                }
                case $this->QR_MODE_AN: {
                    $length = $this->eatAn();
                    break;
                }
                case $this->QR_MODE_KJ: {
                    if ($hint == $this->QR_MODE_KJ) {
                        $length = $this->eatKanji();
                    } else {
                        $length = $this->eat8();
                    }
                    break;
                }
                default: {
                    $length = $this->eat8();
                    break;
                }
            }
            if ($length == 0) {
                return 0;
            }
            if ($length < 0) {
                return -1;
            }
            $this->dataStr = substr($this->dataStr, $length);
        }
    }

    /**
     * toUpper
     */
     protected function toUpper() {
        $stringLen = strlen($this->dataStr);
        $p = 0;
        while ($p < $stringLen) {
            $mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
            if ($mode == $this->QR_MODE_KJ) {
                $p += 2;
            } else {
                if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
                    $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
                }
                $p++;
            }
        }
        return $this->dataStr;
    }

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

    // QRinputItem

    /**
     * newInputItem
     * @param int $mode
     * @param int $size
     * @param array $data
     * @param array $bstream
     * @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)) {
            return NULL;
        }
        $inputitem = array();
        $inputitem['mode'] = $mode;
        $inputitem['size'] = $size;
        $inputitem['data'] = $setData;
        $inputitem['bstream'] = $bstream;
        return $inputitem;
    }

    /**
     * encodeModeNum
     * @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->lengthIndicator($this->QR_MODE_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;
    }

    /**
     * encodeModeAn
     * @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(v, $this->lengthIndicator($this->QR_MODE_AN, $version), $inputitem['size']);
        for ($i=0; $i < $words; ++$i) {
            $val  = (int)$this->lookAnTable(ord($inputitem['data'][$i*2  ])) * 45;
            $val += (int)$this->lookAnTable(ord($inputitem['data'][$i*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;
    }

    /**
     * encodeMode8
     * @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->lengthIndicator($this->QR_MODE_8B, $version), $inputitem['size']);
        for ($i=0; $i < $inputitem['size']; ++$i) {
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
        }
        return $inputitem;
    }

    /**
     * encodeModeKanji
     * @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->lengthIndicator($this->QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
        for ($i=0; $i<$inputitem['size']; $i+=2) {
            $val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
            if ($val <= 0x9ffc) {
                $val -= 0x8140;
            } else {
                $val -= 0xc140;
            }
            $h = ($val >> 8) * 0xc0;
            $val = ($val & 0xff) + $h;
            $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
        }
        return $inputitem;
    }

    /**
     * encodeModeStructure
     * @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;
    }

    /**
     * encodeBitStream
     * @param array $inputitem
     * @param int $version
     * @return array input item
     */
     protected function encodeBitStream($inputitem, $version) {
        $inputitem['bstream'] = array();
        $words = $this->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 $this->QR_MODE_NM: {
                    $inputitem = $this->encodeModeNum($inputitem, $version);
                    break;
                }
                case $this->QR_MODE_AN: {
                    $inputitem = $this->encodeModeAn($inputitem, $version);
                    break;
                }
                case $this->QR_MODE_8B: {
                    $inputitem = $this->encodeMode8($inputitem, $version);
                    break;
                }
                case $this->QR_MODE_KJ: {
                    $inputitem = $this->encodeModeKanji($inputitem, $version);
                    break;
                }
                case $this->QR_MODE_ST: {
                    $inputitem = $this->encodeModeStructure($inputitem);
                    break;
                }
                default: {
                    break;
                }
            }
        }
        return $inputitem;
    }

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

    // QRinput

    /**
     * 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 items
     *
     */
    protected function appendNewInputItem($items, $mode, $size, $data) {
        $items[] = $this->newInputItem($mode, $size, $data);
        return $items;
    }

    /**
     * insertStructuredAppendHeader
     * @param array $items
     * @param int $size
     * @param int $index
     * @param int $parity
     * @return array items
     */
     protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
        if ($size > $this->MAX_STRUCTURED_SYMBOLS) {
            return -1;
        }
        if (($index <= 0) OR ($index > $this->MAX_STRUCTURED_SYMBOLS)) {
            return -1;
        }
        $buf = array($size, $index, $parity);
        $entry = $this->newInputItem($this->QR_MODE_ST, 3, buf);
        array_unshift($items, $entry);
        return $items;
    }

    /**
     * calcParity
     * @param array $items
     * @return int parity
     */
     protected function calcParity($items) {
        $parity = 0;
        foreach ($items as $item) {
            if ($item['mode'] != $this->QR_MODE_ST) {
                for ($i=$item['size']-1; $i>=0; --$i) {
                    $parity ^= $item['data'][$i];
                }
            }
        }
        return $parity;
    }

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

    /**
     * estimateBitsModeNum
     * @param int $size
     * @return int number of bits
     */
     protected function estimateBitsModeNum($size) {
        $w = (int)$size / 3;
        $bits = $w * 10;
        switch($size - $w * 3) {
            case 1: {
                $bits += 4;
                break;
            }
            case 2: {
                $bits += 7;
                break;
            }
            default: {
                break;
            }
        }
        return $bits;
    }

    /**
     * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
     * @param int $c character value
     * @return value
     */
    protected function lookAnTable($c) {
        return (($c > 127)?-1:$this->anTable[$c]);
    }

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

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

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

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

    /**
     * checkModeKanji
     * @param int $size
     * @param array $data
     * @return boolean true or false
     */
     protected function checkModeKanji($size, $data) {
        if ($size & 1) {
            return false;
        }
        for ($i=0; $i<$size; $i+=2) {
            $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
            if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 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 $this->QR_MODE_NM: {
                return $this->checkModeNum($size, $data);
            }
            case $this->QR_MODE_AN: {
                return $this->checkModeAn($size, $data);
            }
            case $this->QR_MODE_KJ: {
                return $this->checkModeKanji($size, $data);
            }
            case $this->QR_MODE_8B: {
                return true;
            }
            case $this->QR_MODE_ST: {
                return true;
            }
            default: {
                break;
            }
        }
        return false;
    }

    /**
     * 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 $this->QR_MODE_NM: {
                    $bits = $this->estimateBitsModeNum($item['size']);
                    break;
                }
                case $this->QR_MODE_AN: {
                    $bits = $this->estimateBitsModeAn($item['size']);
                    break;
                }
                case $this->QR_MODE_8B: {
                    $bits = $this->estimateBitsMode8($item['size']);
                    break;
                }
                case $this->QR_MODE_KJ: {
                    $bits = $this->estimateBitsModeKanji($item['size']);
                    break;
                }
                case $this->QR_MODE_ST: {
                    return $this->STRUCTURE_HEADER_BITS;
                }
                default: {
                    return 0;
                }
            }
            $l = $this->lengthIndicator($item['mode'], $version);
            $m = 1 << $l;
            $num = (int)(($item['size'] + $m - 1) / $m);
            $bits += $num * (4 + $l);
        }
        return $bits;
    }

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

    /**
     * lengthOfCode
     * @param int $mode
     * @param int $version
     * @param int $bits
     * @return int size
     */
     protected function lengthOfCode($mode, $version, $bits) {
        $payload = $bits - 4 - $this->lengthIndicator($mode, $version);
        switch($mode) {
            case $this->QR_MODE_NM: {
                $chunks = (int)($payload / 10);
                $remain = $payload - $chunks * 10;
                $size = $chunks * 3;
                if ($remain >= 7) {
                    $size += 2;
                } elseif ($remain >= 4) {
                    $size += 1;
                }
                break;
            }
            case $this->QR_MODE_AN: {
                $chunks = (int)($payload / 11);
                $remain = $payload - $chunks * 11;
                $size = $chunks * 2;
                if ($remain >= 6) {
                    ++$size;
                }
                break;
            }
            case $this->QR_MODE_8B: {
                $size = (int)($payload / 8);
                break;
            }
            case $this->QR_MODE_KJ: {
                $size = (int)(($payload / 13) * 2);
                break;
            }
            case $this->QR_MODE_ST: {
                $size = (int)($payload / 8);
                break;
            }
            default: {
                $size = 0;
                break;
            }
        }
        $maxsize = $this->maximumWords($mode, $version);
        if ($size < 0) {
            $size = 0;
        }
        if ($size > $maxsize) {
            $size = $maxsize;
        }
        return $size;
    }

    /**
     * createBitStream
     * @param array $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);
    }

    /**
     * convertData
     * @param array $items
     * @return array items
     */
     protected function convertData($items) {
        $ver = $this->estimateVersion($items);
        if ($ver > $this->version) {
            $this->version = $ver;
        }
        for (;;) {
            $cbs = $this->createBitStream($items);
            $items = $cbs[0];
            $bits = $cbs[1];
            if ($bits < 0) {
                return -1;
            }
            $ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
            if ($ver < 0) {
                return -1;
            } elseif ($ver > $this->version) {
                $this->version = $ver;
            } else {
                break;
            }
        }
        return $items;
    }

    /**
     * Append Padding Bit to bitstream
     * @param array $bstream
     * @return array bitstream
     */
     protected function appendPaddingBit($bstream) {
        $bits = count($bstream);
        $maxwords = $this->getDataLength($this->version, $this->level);
        $maxbits = $maxwords * 8;
        if ($maxbits == $bits) {
            return 0;
        }
        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 ($i=0; $i<$padlen; ++$i) {
                $padbuf[$i] = ($i&1)?0x11:0xec;
            }
            $padding = $this->appendBytes($padding, $padlen, $padbuf);
        }
        return $this->appendBitstream($bstream, $padding);
    }

    /**
     * mergeBitStream
     * @param array $bstream
     * @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;
    }

    /**
     * Returns a stream of bits.
     * @param int $items
     * @return array padded merged byte stream
     */
    protected function getBitStream($items) {
        $bstream = $this->mergeBitStream($items);
        return $this->appendPaddingBit($bstream);
    }

    /**
     * Pack all bit streams padding bits into a byte array.
     * @param int $items
     * @return array padded merged byte stream
     */
    protected function getByteStream($items) {
        $bstream = $this->getBitStream($items);
        return $this->bitstreamToByte($bstream);
    }

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

    // QRbitstream

    /**
     * Return an array with zeros
     * @param int $setLength array size
     * @return array
     */
     protected function allocate($setLength) {
        return array_fill(0, $setLength, 0);
    }

    /**
     * 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 ($i=0; $i<$bits; ++$i) {
            if ($num & $mask) {
                $bstream[$i] = 1;
            } else {
                $bstream[$i] = 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);
        $p=0;
        for ($i=0; $i<$size; ++$i) {
            $mask = 0x80;
            for ($j=0; $j<8; ++$j) {
                if ($data[$i] & $mask) {
                    $bstream[$p] = 1;
                } else {
                    $bstream[$p] = 0;
                }
                $p++;
                $mask = $mask >> 1;
            }
        }
        return $bstream;
    }

    /**
     * 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)) OR (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;
        }
        $b = $this->newFromNum($bits, $num);
        return $this->appendBitstream($bitstream, $b);
    }

    /**
     * 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;
        }
        $b = $this->newFromBytes($size, $data);
        return $this->appendBitstream($bitstream, $b);
    }

    /**
     * Convert bitstream to bytes
     * @param array $bitstream 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);
        $p = 0;
        for ($i=0; $i<$bytes; $i++) {
            $v = 0;
            for ($j=0; $j<8; $j++) {
                $v = $v << 1;
                $v |= $bstream[$p];
                $p++;
            }
            $data[$i] = $v;
        }
        if ($size & 7) {
            $v = 0;
            for ($j=0; $j<($size & 7); $j++) {
                $v = $v << 1;
                $v |= $bstream[$p];
                $p++;
            }
            $data[$bytes] = $v;
        }
        return $data;
    }

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

    // QRspec

    /**
     * Replace a value on the array at the specified position
     * @param array $srctab
     * @param int $x X position
     * @param int $y Y position
     * @param string $repl value to replace
     * @param int $replLen length of the repl string
     * @return array srctab
     */
     protected function qrstrset($srctab, $x, $y, $repl, $replLen=false) {
        $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($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)
     */
    protected function getDataLength($version, $level) {
        return $this->capacity[$version][$this->QRCAP_WORDS] - $this->capacity[$version][$this->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)
     */
    protected function getECCLength($version, $level){
        return $this->capacity[$version][$this->QRCAP_EC][$level];
    }

    /**
     * Return the width of the symbol for the version.
     * @param int $version version
     * @return int width
     */
    protected function getWidth($version) {
        return $this->capacity[$version][$this->QRCAP_WIDTH];
    }

    /**
     * Return the numer of remainder bits.
     * @param int $version version
     * @return int number of remainder bits
     */
    protected function getRemainder($version) {
        return $this->capacity[$version][$this->QRCAP_REMINDER];
    }

    /**
     * Return a version number that satisfies the input code length.
     * @param int $size input code length (byte)
     * @param int $level error correction level
     * @return int version number
     */
    protected function getMinimumVersion($size, $level) {
        for ($i=1; $i <= $this->QRSPEC_VERSION_MAX; ++$i) {
            $words  = $this->capacity[$i][$this->QRCAP_WORDS] - $this->capacity[$i][$this->QRCAP_EC][$level];
            if ($words >= $size) {
                return $i;
            }
        }
        return -1;
    }

    /**
     * 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).
     */
    protected function lengthIndicator($mode, $version) {
        if ($mode == $this->QR_MODE_ST) {
            return 0;
        }
        if ($version <= 9) {
            $l = 0;
        } elseif ($version <= 26) {
            $l = 1;
        } else {
            $l = 2;
        }
        return $this->lengthTableBits[$mode][$l];
    }

    /**
     * Return the maximum length for the mode and version.
     * @param int $mode encoding mode
     * @param int $version version
     * @return int the maximum length (bytes)
     */
    protected function maximumWords($mode, $version) {
        if ($mode == $this->QR_MODE_ST) {
            return 3;
        }
        if ($version <= 9) {
            $l = 0;
        } else if ($version <= 26) {
            $l = 1;
        } else {
            $l = 2;
        }
        $bits = $this->lengthTableBits[$mode][$l];
        $words = (1 << $bits) - 1;
        if ($mode == $this->QR_MODE_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 an 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
     */
    protected function getEccSpec($version, $level, $spec) {
        if (count($spec) < 5) {
            $spec = array(0, 0, 0, 0, 0);
        }
        $b1 = $this->eccTable[$version][$level][0];
        $b2 = $this->eccTable[$version][$level][1];
        $data = $this->getDataLength($version, $level);
        $ecc = $this->getECCLength($version, $level);
        if ($b2 == 0) {
            $spec[0] = $b1;
            $spec[1] = (int)($data / $b1);
            $spec[2] = (int)($ecc / $b1);
            $spec[3] = 0;
            $spec[4] = 0;
        } else {
            $spec[0] = $b1;
            $spec[1] = (int)($data / ($b1 + $b2));
            $spec[2] = (int)($ecc  / ($b1 + $b2));
            $spec[3] = $b2;
            $spec[4] = $spec[1] + 1;
        }
        return $spec;
    }

    /**
     * Put an alignment marker.
     * @param array $frame frame
     * @param int $width width
     * @param int $ox X center coordinate of the pattern
     * @param int $oy Y center coordinate of the pattern
     * @return array frame
     */
    protected function putAlignmentMarker($frame, $ox, $oy) {
        $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 = $oy - 2;
        $xStart = $ox - 2;
        for ($y=0; $y < 5; $y++) {
            $frame = $this->qrstrset($frame, $xStart, $yStart+$y, $finder[$y]);
        }
        return $frame;
    }

    /**
     * Put an alignment pattern.
     * @param int $version version
     * @param array $fram frame
     * @param int $width width
     * @return array frame
     */
     protected function putAlignmentPattern($version, $frame, $width) {
        if ($version < 2) {
            return $frame;
        }
        $d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0];
        if ($d < 0) {
            $w = 2;
        } else {
            $w = (int)(($width - $this->alignmentPattern[$version][0]) / $d + 2);
        }
        if ($w * $w - 3 == 1) {
            $x = $this->alignmentPattern[$version][0];
            $y = $this->alignmentPattern[$version][0];
            $frame = $this->putAlignmentMarker($frame, $x, $y);
            return $frame;
        }
        $cx = $this->alignmentPattern[$version][0];
        $wo = $w - 1;
        for ($x=1; $x < $wo; ++$x) {
            $frame = $this->putAlignmentMarker($frame, 6, $cx);
            $frame = $this->putAlignmentMarker($frame, $cx,  6);
            $cx += $d;
        }
        $cy = $this->alignmentPattern[$version][0];
        for ($y=0; $y < $wo; ++$y) {
            $cx = $this->alignmentPattern[$version][0];
            for ($x=0; $x < $wo; ++$x) {
                $frame = $this->putAlignmentMarker($frame, $cx, $cy);
                $cx += $d;
            }
            $cy += $d;
        }
        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
     */
    protected function getVersionPattern($version) {
        if (($version < 7) OR ($version > $this->QRSPEC_VERSION_MAX)) {
            return 0;
        }
        return $this->versionPattern[($version - 7)];
    }

    /**
     * Return BCH encoded format information pattern.
     * @param array $mask
     * @param int $level error correction level
     * @return BCH encoded format information pattern
     */
    protected function getFormatInfo($mask, $level) {
        if (($mask < 0) OR ($mask > 7)) {
            return 0;
        }
        if (($level < 0) OR ($level > 3)) {
            return 0;
        }
        return $this->formatInfo[$level][$mask];
    }

    /**
     * Put a finder pattern.
     * @param array $frame frame
     * @param int $width width
     * @param int $ox X center coordinate of the pattern
     * @param int $oy Y center coordinate of the pattern
     * @return array frame
     */
    protected function putFinderPattern($frame, $ox, $oy) {
        $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 ($y=0; $y < 7; $y++) {
            $frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
        }
        return $frame;
    }

    /**
     * Return a copy of initialized frame.
     * @param int $version version
     * @return Array of unsigned char.
     */
    protected function createFrame($version) {
        $width = $this->capacity[$version][$this->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 ($y=0; $y < 7; ++$y) {
            $frame[$y][7] = "\xc0";
            $frame[$y][$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 ($y=0; $y < 8; ++$y,++$yOffset) {
            $frame[$y][8] = "\x84";
            $frame[$yOffset][8] = "\x84";
        }
        // Timing pattern
        $wo = $width - 15;
        for ($i=1; $i < $wo; ++$i) {
            $frame[6][7+$i] = chr(0x90 | ($i & 1));
            $frame[7+$i][6] = chr(0x90 | ($i & 1));
        }
        // Alignment pattern
        $frame = $this->putAlignmentPattern($version, $frame, $width);
        // Version information
        if ($version >= 7) {
            $vinf = $this->getVersionPattern($version);
            $v = $vinf;
            for ($x=0; $x<6; ++$x) {
                for ($y=0; $y<3; ++$y) {
                    $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
                    $v = $v >> 1;
                }
            }
            $v = $vinf;
            for ($y=0; $y<6; ++$y) {
                for ($x=0; $x<3; ++$x) {
                    $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
                    $v = $v >> 1;
                }
            }
        }
        // and a little bit...
        $frame[$width - 8][8] = "\x81";
        return $frame;
    }

    /**
     * Set new frame for the specified version.
     * @param int $version version
     * @return Array of unsigned char.
     */
    protected function newFrame($version) {
        if (($version < 1) OR ($version > $this->QRSPEC_VERSION_MAX)) {
            return NULL;
        }
        if (!isset($this->frames[$version])) {
            $this->frames[$version] = $this->createFrame($version);
        }
        if (is_null($this->frames[$version])) {
            return NULL;
        }
        return $this->frames[$version];
    }

    /**
     * Return block number 0
     * @param array $spec
     * @return int value
     */
     protected function rsBlockNum($spec) {
        return ($spec[0] + $spec[3]);
    }

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

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

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

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

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

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

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

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

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

    // QRrs

    /**
     * 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:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
     */
     protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
        foreach ($this->rsitems as $rs) {
            if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
                OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
                continue;
            }
            return $rs;
        }
        $rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
        array_unshift($this->rsitems, $rs);
        return $rs;
    }

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

    // QRrsItem

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

    /**
     * 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:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
     */
    protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
        // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
        $rs = null;
        // Check parameter ranges
        if (($symsize < 0) OR ($symsize > 8)) {
            return $rs;
        }
        if (($fcr < 0) OR ($fcr >= (1<<$symsize))) {
            return $rs;
        }
        if (($prim <= 0) OR ($prim >= (1<<$symsize))) {
            return $rs;
        }
        if (($nroots < 0) OR ($nroots >= (1<<$symsize))) {
            return $rs;
        }
        if (($pad < 0) OR ($pad >= ((1<<$symsize) -1 - $nroots))) {
            return $rs;
        }
        $rs = array();
        $rs['mm'] = $symsize;
        $rs['nn'] = (1 << $symsize) - 1;
        $rs['pad'] = $pad;
        $rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
        $rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
        // PHP style macro replacement ;)
        $NN =& $rs['nn'];
        $A0 =& $NN;
        // Generate Galois field lookup tables
        $rs['index_of'][0] = $A0; // log(zero) = -inf
        $rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
        $sr = 1;
        for ($i=0; $i<$rs['nn']; ++$i) {
            $rs['index_of'][$sr] = $i;
            $rs['alpha_to'][$i] = $sr;
            $sr <<= 1;
            if ($sr & (1 << $symsize)) {
                $sr ^= $gfpoly;
            }
            $sr &= $rs['nn'];
        }
        if ($sr != 1) {
            // field generator polynomial is not primitive!
            return NULL;
        }
        // Form RS code generator polynomial from its roots
        $rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
        $rs['fcr'] = $fcr;
        $rs['prim'] = $prim;
        $rs['nroots'] = $nroots;
        $rs['gfpoly'] = $gfpoly;
        // Find prim-th root of 1, used in decoding
        for ($iprim=1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
            ; // intentional empty-body loop!
        }
        $rs['iprim'] = (int)($iprim / $prim);
        $rs['genpoly'][0] = 1;

        for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
            $rs['genpoly'][$i+1] = 1;
            // Multiply rs->genpoly[] by  @**(root + x)
            for ($j = $i; $j > 0; --$j) {
                if ($rs['genpoly'][$j] != 0) {
                    $rs['genpoly'][$j] = $rs['genpoly'][$j-1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
                } else {
                    $rs['genpoly'][$j] = $rs['genpoly'][$j-1];
                }
            }
            // rs->genpoly[0] can never be zero
            $rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
        }
        // convert rs->genpoly[] to index form for quicker encoding
        for ($i = 0; $i <= $nroots; ++$i) {
            $rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
        }
        return $rs;
    }

    /**
     * Encode a Reed-Solomon codec and returns the parity array
     * @param array $rs RS values
     * @param array $data data
     * @param array $parity parity
     * @return parity array
     */
     protected function encode_rs_char($rs, $data, $parity) {
        $MM       =& $rs['mm']; // bits per symbol
        $NN       =& $rs['nn']; // the total number of symbols in a RS block
        $ALPHA_TO =& $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form
        $INDEX_OF =& $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form
        $GENPOLY  =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
        $NROOTS   =& $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block
        $FCR      =& $rs['fcr']; // first consecutive root, index form
        $PRIM     =& $rs['prim']; // primitive element, index form
        $IPRIM    =& $rs['iprim']; // prim-th root of 1, index form
        $PAD      =& $rs['pad']; // the number of pad symbols in a block
        $A0       =& $NN;
        $parity = array_fill(0, $NROOTS, 0);
        for ($i=0; $i < ($NN - $NROOTS - $PAD); $i++) {
            $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
            if ($feedback != $A0) {
                // feedback term is non-zero
                // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
                // always be for the polynomials constructed by init_rs()
                $feedback = $this->modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
                for ($j=1; $j < $NROOTS; ++$j) {
                $parity[$j] ^= $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
                }
            }
            // Shift
            array_shift($parity);
            if ($feedback != $A0) {
                array_push($parity, $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[0])]);
            } else {
                array_push($parity, 0);
            }
        }
        return $parity;
    }
    
    /**
     * 图片生成方法
     *
     * @param $frame array() 二维码的二维数组
     * @param $pixelPerPoint int 像素
     * @param $outerFrame int 边框像素
     *
     * @return
     *
     */
    protected function image($frame,$pixelPerPoint = 2, $outerFrame = 2)
    {
        $h = count($frame);
        $w = count($frame[0]);
            
        $imgW = $w + 2*$outerFrame;
        $imgH = $h + 2*$outerFrame;
            
        $base_image =ImageCreate($imgW, $imgH);
            
        $col[0] = ImageColorAllocate($base_image,255,255,255);
        $col[1] = ImageColorAllocate($base_image,0,0,0);

        imagefill($base_image, 0, 0, $col[0]);

        for($y=0; $y<$h; $y++) {
            for($x=0; $x<$w; $x++) {
                if ($frame[$y][$x] == '1') {
                    ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]);
                }
            }
        }
            
        $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
        ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
        ImageDestroy($base_image);
            
        return $target_image;
    }
    
    /**
     *
     * png二维码
     *
     * @param $str string 字符串 要生成二维码的字符串
     * @param $filename string 文件名
     * @param $eclevel string <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
     * @param $pixelPerPoint int 像素
     * @param $outerFrame int
     * @param $q int
     *
     * @return null
     *
     */
    public function png($str = '', $filename = false, $eclevel = "H", $pixelPerPoint = 8, $outerFrame = 2, $q = 85)
    {
        $this->set($str,$eclevel);
        $image = $this->image($this->barcode_array['bcode'], $pixelPerPoint, $outerFrame);
        // dump($image);die;
        if ($filename === false) {

    // 从这里开始修改
            //二维码logo
            $logo = "./Public/images/logo1.png";
            $logo = imagecreatefromstring(file_get_contents($logo));
            $QR_width = imagesx($image);
            $QR_height = imagesy($image);
            $logo_width = imagesx($logo);
            $logo_height = imagesy($logo);
            $logo_qr_width = $QR_width / 5;
            $scale = $logo_width / $logo_qr_width;
            $logo_qr_height = $logo_height / $scale;
            $from_width = ($QR_width - $logo_qr_width) / 2;
            imagecopyresampled($image, $logo, $from_width, $from_width, 0, 0, $logo_qr_width, $logo_qr_height, $logo_width, $logo_height);
            Header("Content-type: image/png");
            imagepng($image);  
        } else {
            if($saveandprint===TRUE){
                ImagePng($image, $filename);
                header("Content-type: image/png");
                ImagePng($image);
             }else{
                ImagePng($image, $filename);
            }
        }
            
        ImageDestroy($image);
    }
    
    
    /**
     *
     * jpg二维码
     *
     * @param $str string 字符串 要生成二维码的字符串
     * @param $filename string 文件名
     * @param $eclevel string <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
     * @param $pixelPerPoint int 像素
     * @param $outerFrame int
     * @param $q int
     *
     * @return null
     *
     */
    public function jpg($str = '', $filename = false, $eclevel = "H", $pixelPerPoint = 8, $outerFrame = 2, $q = 85)
    {
        $this->set($str,$eclevel);
        $image = $this->image($this->barcode_array['bcode'], $pixelPerPoint, $outerFrame);
            
        if ($filename === false) {
            Header("Content-type: image/jpeg");
            ImageJpeg($image, null, $q);
        } else {
            ImageJpeg($image, $filename, $q);            
        }
        ImageDestroy($image);
    }
    
    

} // end QRcode class

微信支付生成带logo的二维码的更多相关文章

  1. PHP生成带logo图像二维码的两种方法

    本文主要和大家分享PHP生成带logo图像二维码的两种方法,主要以文字和代码的形式和大家分享,希望能帮助到大家. 一.利用Google API生成二维码Google提供了较为完善的二维码生成接口,调用 ...

  2. C#生成带logo的二维码

    带logo的二维码生成分为两步骤:首先根据输入的内容生成二维码图片,然后读取本地的logo图片,通过图片处理生成带logo的二维码. 生成的二维码效果如下: 下面直接贴出二维码生成类   QRCode ...

  3. .NET生成带Logo的二维码

    使用ThoughtWorks.QRCode生成,利用这个库来生成带Logo的二维码(就是中间嵌了一个图片的二维码),直接见代码: HttpContext context = HttpContext.C ...

  4. C# ZXing.Net生成二维码、识别二维码、生成带Logo的二维码(二)

    1.使用ZXint.Net生成带logo的二维码 /// <summary> /// 生成带Logo的二维码 /// </summary> /// <param name ...

  5. 涛哥的Python脚本工具箱之生成带Logo的二维码

    近期须要在二维码上加Logo,网上没有找到好用的,于是自己用python写了一个. 须要安装qrcode,PIL库 二维码简称 QR Code(Quick Response Code),学名为高速响应 ...

  6. phpqrcode生成带logo的二维码图片及带文字的二维码图片

    <?php require_once "./phpqrcode/phpqrcode.php"; /** * 这样就可以生成二维码了,实际上在png这个方法里还有几个参数需要使 ...

  7. jQuery-qrcode.js 生成带Logo 的二维码

    引入文件  jQuery-qrcode.js 地址:https://blog-static.cnblogs.com/files/kitty-blog/jquery-qrcode.js https:// ...

  8. JAVA生成带Logo的二维码

    1.下载生成二维码所需要的jar包qrcode.jar: 2.直接上生成二维码的java代码 //需要导入的包 import java.awt.Color;import java.awt.Graphi ...

  9. js生成带logo的二维码

    作为一名java程序员,一直以来都是使用服务端生成二维码,最近接触前端的设计,感觉二维码这块如果放到前端去生成,一方面可以减轻服务端的压力,访问带宽,另一方面,前端页面控制比较顺畅 闲话少叙,说下我的 ...

随机推荐

  1. hdu2819二分图匹配

    Given an N*N matrix with each entry equal to 0 or 1. You can swap any two rows or any two columns. C ...

  2. Map遍历四种常用方法

    Map常用四种遍历方式 一: Map<String,String> map = new HashMap<String,String>(); for(String key:map ...

  3. 阿里云主机试用之自建站点和ftp上传所遇的2个问题

    1.Access to the requested object is only available from the local network 其实我并没有自建站点,只是使用了XAMPP来建了ap ...

  4. IOS打包相关问题

    使用了AFNetworking框架,模拟器和真机运行都不报错,但是提交商店报错Unsupported Architecture. Your executable contains unsupporte ...

  5. PHP自定义函数

    啊哈

  6. jgs--多线程和synchronized

    多线程 多线程是我们开发人员经常提到的一个名词.为什么会有多线程的概念呢?我们的电脑有可能会有多个cpu(或者CPU有多个内核)这就产生了多个线程.对于单个CPU来说,由于CPU运算很快,我们在电脑上 ...

  7. 纯真IP数据库格式详解

    纯真版IP数据库,优点是记录多,查询速度快,它只用一个文件QQWry.dat就包含了所有记录,方便嵌入到其他程序中,也方便升级.缺点是你想要编辑它却是比较麻烦的,由于其文件格式的限制,你要直接添加IP ...

  8. CentOS6.5_x86安装Mysql5.5.49

    1.说明: 安装MySQL主要有两种方法:一种是通过源码自行编译安装,这种适合高级用户定制MySQL的特性,这里不做说明:另一种是通过编译过的二进制文件进行安装.二进制文件安装的方法又分为两种:一种是 ...

  9. MySQL ProxySQL读写分离实践

    目的 在上一篇文章MySQL ProxySQL读写分离使用初探里初步介绍了ProxySQL的使用,本文继续介绍它的一些特点和DBProxy的性能差异.深入一些去了解ProxySQL,通过测试来说明Pr ...

  10. (window,parent,opener,top).location.reload方法汇总

    今天在火狐浏览器上碰到个bug,调用parent.location.reload()时只刷新子页面,没有整个浏览器刷新,谷歌上没有问题,网上搜了一下 改成parent.location.reload( ...