<?php
 /**
 * @package Генерация QR-кода
 *
 * @author Павел Новицкий <lugebox@gmail.com>
 * @link http://www.e-luge.net/
 */
class QR{
    /**
     *  пользовательский текст
     *
     *  @var string
     */
    private $data;

    /**
     *  размер введённых даных
     *
     *  @var int
     */
    private $datalength;

    /**
     *  код коррекции ошибок
     *  (L, M, Q, H )
     *  по умолчанию M
     *
     *  @var char
     */
    private $ecc;

    /**
     *  размер изображения
     *  (1-50)
     *  по умолчанию 10
     *
     *  @var int
     */
     private $size;

    /**
     *  тип изображения
     *  (jpeg, png)
     *  по умолчанию png
     *
     *  @var int
     */
     private $type;

    /**
     *  путь к файлам данных QR кодов
     *
     *  @var string
     */
    private $path;

    /**
     *  кодирование кодов коррекции
     *
     *  @var array
     */
    private static $ecc_hash=array('L'=>'1','l'=>'1','M'=>'0','m'=>'0','Q'=>'3',
                                   'q'=>'3','H'=>'2','h'=>'2');

    /**
     *  кодирование символов
     *
     *  @var array
     */
    private static $alphanumeric_hash=array('0'=>0,'1'=>1,'2'=>2,'3'=>3,'4'=>4,
    '5'=>5,'6'=>6,'7'=>7,'8'=>8,'9'=>9,'A'=>10,'B'=>11,'C'=>12,'D'=>13,'E'=>14,
    'F'=>15,'G'=>16,'H'=>17,'I'=>18,'J'=>19,'K'=>20,'L'=>21,'M'=>22,'N'=>23,
    'O'=>24,'P'=>25,'Q'=>26,'R'=>27,'S'=>28,'T'=>29,'U'=>30,'V'=>31,
    'W'=>32,'X'=>33,'Y'=>34,'Z'=>35,' '=>36,'$'=>37,'%'=>38,'*'=>39,
    '+'=>40,'-'=>41,'.'=>42,'/'=>43,':'=>44);

    /**
     *  битовое положение в файлам данных QR кодов
     *
     *  @array
     */
    private static  $data_bits=array(
    0,128,224,352,512,688,864,992,1232,1456,1728,
    2032,2320,2672,2920,3320,3624,4056,4504,5016,5352,
    5712,6256,6880,7312,8000,8496,9024,9544,10136,10984,
    11640,12328,13048,13800,14496,15312,15936,16816,17728,18672,

    152,272,440,640,864,1088,1248,1552,1856,2192,
    2592,2960,3424,3688,4184,4712,5176,5768,6360,6888,
    7456,8048,8752,9392,10208,10960,11744,12248,13048,13880,
    14744,15640,16568,17528,18448,19472,20528,21616,22496,23648,

    72,128,208,288,368,480,528,688,800,976,
    1120,1264,1440,1576,1784,2024,2264,2504,2728,3080,
    3248,3536,3712,4112,4304,4768,5024,5288,5608,5960,
    6344,6760,7208,7688,7888,8432,8768,9136,9776,10208,

    104,176,272,384,496,608,704,880,1056,1232,
    1440,1648,1952,2088,2360,2600,2936,3176,3560,3880,
    4096,4544,4912,5312,5744,6032,6464,6968,7288,7880,
    8264,8920,9368,9848,10288,10832,11408,12016,12656,13328
    );

    /*
     * побитовая разбивка
     */
    private static  $format_inf=array('101010000010010','101000100100101',
    '101111001111100','101101101001011','100010111111001','100000011001110',
    '100111110010111','100101010100000','111011111000100','111001011110011',
    '111110110101010','111100010011101','110011000101111','110001100011000',
    '110110001000001','110100101110110','001011010001001','001001110111110',
    '001110011100111','001100111010000','000011101100010','000001001010101',
    '000110100001100','000100000111011','011010101011111','011000001101000',
    '011111100110001','011101000000110','010010010110100','010000110000011',
    '010111011011010','010101111101101');

    private $patterns=array('b'=>'iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAMAAACeL25MAAADAFBMVEUAAACAgICAAACAgAAAgAAAgIAAAICAAICAgEAAQEAAgP8AQIBAAP+AQAD////AwMD/AAD//wAA/wAA//8AAP//AP///4AA/4CA//+AgP//AID/gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkHZX0AAAADklEQVR4nGPgAwIGVAIACNQA4aH1GJsAAAAASUVORK5CYII=','d'=>'iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAMAAACeL25MAAADAFBMVEUAAACAgICAAACAgAAAgAAAgIAAAICAAICAgEAAQEAAgP8AQIBAAP+AQAD////AwMD/AAD//wAA/wAA//8AAP//AP///4AA/4CA//+AgP//AID/gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkHZX0AAAAC0lEQVR4nGNgwAQAABQAAX3+Hu4AAAAASUVORK5CYII=','qrv1'=>'iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdAQMAAABsXfVMAAAABlBMVEUAAAD///+l2Z/dAAAAPklEQVR4nGP4////DwY04oP8gQqG7/fvVzB8ib+ITIDFPog6VEAV34drQ2N9B5sCJL6DuF/iUQiwGFgWi+UA1Klkqp3gt4kAAAAASUVORK5CYII=','qrv10'=>'iVBORw0KGgoAAAANSUhEUgAAAEEAAABBAQMAAAC0OVsGAAAABlBMVEUAAAD///+l2Z/dAAAAmElEQVR4nGP4DwUNDPhZH+RB9Bn2Bobv90Gst98bGL7Eg1hnxWGstxDWH3kwC6ju7/3/d4HqPoiGAkEIO9i8v/chJt8HqUOz7T4WFwwmMXaQmz/UA1nlIH98B7HC//+N//8VVQyhbuDdjEXs63wY60M9kjqYm7/D/AGMc6jfIHEJEoPE74d6WJyD9CJY3+G2QdIL4XQFZwEAAyEBzAFPbYcAAAAASUVORK5CYII=','qrv11'=>'iVBORw0KGgoAAAANSUhEUgAAAEUAAABFAQMAAAAmQ7lqAAAABlBMVEUAAAD///+l2Z/dAAAAlElEQVR4nGP4DwU/GPCzPsiD6H8OFQzf74NZ8RUMX+JBrD+BMNZfKIv9/5+LEHXl///er2D4IBoKAkC9IFXlEJPvg9Sh2XYfiwsGuxg72B/sQFY52G/lQFb4fzBCEUOoG3g3Eyn2Rx7G+lgPY324D/fHd5jfQGkD4l9InIPEIOkApA6SNkB6EazvcNs+wO1Acgs+FgDnczyR2YwyRwAAAABJRU5ErkJggg==','qrv12'=>'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJAQMAAABLvZmfAAAABlBMVEUAAAD///+l2Z/dAAAAlUlEQVR4nGP4DwMNDASZH+TBjDfsDQzf74OZX783MHyJBzOvisOZZ6HMg0AF4hC1d4EIqPaDaCgIhLBDzL0LteI+WC26xfexOmd4iLKDffyhHsgsB4fDdxAzHBiMwDBDE0VSO8h8QbHon/lw5jeE6M94hI+/w8MBlPqgoQNNUSDRLwi10NQHMgGJ+R1hMTT9EpXWEUwAhOmSBu1sT6EAAAAASUVORK5CYII=','qrv13'=>'iVBORw0KGgoAAAANSUhEUgAAAE0AAABNAQMAAADZx3vzAAAABlBMVEUAAAD///+l2Z/dAAAAlklEQVR4nGP4DwM/GAgyP8iDGX8cKhi+34cI3q9g+BIPZv29CGf+D4QwP9T//xsIUfsdyASq/SAaCgZAE0DqgKJgK+6D1aJbfB+rc4azKDskHNiBzHJI6JQDmeH//38FMsNRRZHUDjJf0Ej0qzyc+R0h+i0eEQ7f4aEDSqnQMIOmPpDoF4RaWEr9j8KEpWpEWicqXyCYAIO00tSNZcuBAAAAAElFTkSuQmCC','qrv14'=>'iVBORw0KGgoAAAANSUhEUgAAAFEAAABRAQMAAACQQdh1AAAABlBMVEUAAAD///+l2Z/dAAAAnUlEQVR4nGP4DwcNDMSwP8hDWFfYGxi+34ew735vYPgSD2H/FUewz0LYH+r/s/9/Kg5W/73+fzlY/QfRUDAIYQebDxYH23Ufoh7DDfdxuG2wibND3P+hHsguh/jrO4gd/v9rPZhAE0dWPxjcP+pfMPvTfAT7Xz2C/T0eyf3fEf4C5gu4f2HpHCT+BUk9LF+AzEFmw/IRcv4iNj8isQEivhD8FrGUxwAAAABJRU5ErkJggg==','qrv15'=>'iVBORw0KGgoAAAANSUhEUgAAAFUAAABVAQMAAAACOzoZAAAABlBMVEUAAAD///+l2Z/dAAAAnklEQVR4nGP4Dwc/GIhhf5CHMg9UMHy/D2H+ja9g+BIPFQ/EYH+o/3/w/59AsPrv9f/v/v97v4Lhg2goBDhUgMwHi4Ptug9Rj+GG+zjcNtjE2aHuZweyy6H+Kgeyw/9/rf9/9f//cDRxZPWDwf2j4UCW+G95JPF6BPtHPJK/viP8C8xH8HCA5QuQ+Bck9fB89B+VDct3KPmRyPyLxAYA0JxnyKZ5eLwAAAAASUVORK5CYII=','qrv16'=>'iVBORw0KGgoAAAANSUhEUgAAAFkAAABZAQMAAABvxRrsAAAABlBMVEUAAAD///+l2Z/dAAAAnElEQVR4nGP4jwANDERyPshDmX/YGxi+34dyjn5vYPgSD+VcFcfkfKgHob/iYD3f60HoLVDPB9FQCAhhB9sDkQFbeh+qB9M595E5Q0aGHeqfD/VATjnUp99BnPD/X+shCF0GRc8g8w+9ZEbDDY/MD2SZ3/tRZZDC4DtS6ABzMCLc4LkRJAPPpx/qkXIwyDQUzndkS+HlAQllCDIHAMoLwOeLbQvLAAAAAElFTkSuQmCC','qrv17'=>'iVBORw0KGgoAAAANSUhEUgAAAF0AAABdAQMAAAD9v/iAAAAABlBMVEUAAAD///+l2Z/dAAAAmUlEQVR4nGP4jwA/GIjkfJCHMv86VDB8vw/l/LlfwfAlHiZzEYnzD8phByGQDEhPOQj9A+r5IBoKBUDTQMrBMmBL70P1YDrnPjJnWMuww8KAHcgph4VOOZAT/h+G0GVQ9Awy/9BLZjTc8Mh8jEfi/NqPxAFlTUQYfEcKHVCuh4cbPAeDZOB5G6TnC7LRKBx4SYFShpBQ7iBzANArDxDm87+yAAAAAElFTkSuQmCC','qrv18'=>'iVBORw0KGgoAAAANSUhEUgAAAGEAAABhAQMAAAD8yF3gAAAABlBMVEUAAAD///+l2Z/dAAAAo0lEQVR4nGP4jwQaGIjnfZCHsY+wNzB8vw/jvf3ewPAlHsb7K47Muwrlsf//fxCoUhyir/z//7sQfR9EQ6EghB1iH0QObPt9mD4sLruPwhtZcuywcPlQD+SVw8LsO4gX/h+Erv7//xVTDlXf4PXfYJIbDWuqyn1Dkftsjy6HFGbfkcMTVPYgwhpRhoDkEOXLh3rksgdkJioPUWahlmeklYMoPAChVH7FEFQF8gAAAABJRU5ErkJggg==','qrv19'=>'iVBORw0KGgoAAAANSUhEUgAAAGUAAABlAQMAAABusr+MAAAABlBMVEUAAAD///+l2Z/dAAAAp0lEQVR4nGP4jwR+MBDP+yAPY/87UMHw/T6cF1/B8CUerjAQmffvIoTH/v//h/r/fy5C9JX///+9/v+/+xUMH0RDYcChAmwfRA5s+32YPiwuu4/CG1ly7PBwYQfyyuFhVg7khf8Hoa9AXjiGHKq+weu/oSI3Gg/0k4tH5n2yR+b9vI8Snt+RwxpUZiHiAVH2gOQQ5RJI3xcUG1B5iLIOtRwkrfxE4QEApfPUl76SxB0AAAAASUVORK5CYII=','qrv2'=>'iVBORw0KGgoAAAANSUhEUgAAACEAAAAhAQMAAABtKlAsAAAABlBMVEUAAAD///+l2Z/dAAAAUElEQVR4nGP4DwQNDJjkB/k/7A0M3+///d7A8CX+rzgqCRH/IBrCDtd1H8kEotgf6oHk9+/1ILu+1oPMBLG/xH8AkyA1EPL7fYh7sLsTTAIA+1GCxeYLlGYAAAAASUVORK5CYII=','qrv20'=>'iVBORw0KGgoAAAANSUhEUgAAAGkAAABpAQMAAAADTJ95AAAABlBMVEUAAAD///+l2Z/dAAAApElEQVR4nGP4jwwaGEjifpCHc56wNzB8vw/nfv3ewPAlHs59Ko7C/Qrlfqj//58dwgXp/Q7klv///xao94NoKAyEsEPshcqCnXEfrhebI++jckdlyZZlh4fzh3ogtxweC99B3HBg1AG5YApTFk3vIPHR8JMdjaPBJ/t1Pwr3QzxqOH9HiQVQKYoUR0glIUj2C6pepFIUZDIaF6kERiufSS7bUbkAZY5DRjGALDoAAAAASUVORK5CYII=','qrv21'=>'iVBORw0KGgoAAAANSUhEUgAAAG0AAABtAQMAAACRNn0VAAAABlBMVEUAAAD///+l2Z/dAAAAtElEQVR4nGP4jwx+MJDE/SAP5/w5UMHw/T5C8n4Fw5d4OO/fRRTuHwj3j/z/D/X/D/7/GwjW+/f+/+/1/+/+/wfU+0E0FA4cKkD2wmTBzrgP14vNkfdRucNelh0RGuxAbjkirMqB3PD/f+P/f63/f/X//3BMWTS9g8RHAyU7GpLUkh0NSaJlv8WjcL/sR1Ucjxoa31HCClgCI4ckUikKkv2CqvcLmkWoXOTSG7VsJ7leQOUCANYhmxmTBIe0AAAAAElFTkSuQmCC','qrv22'=>'iVBORw0KGgoAAAANSUhEUgAAAHEAAABxAQMAAADYsN6TAAAABlBMVEUAAAD///+l2Z/dAAAApklEQVR4nGP4jwIaGEjlf5BH8O6wNzB8v4/g3/3ewPAlHsE/K47K/wrhf6iHoqfiYP3f66HoLVD/B9FQOAhhB9sPlwe75z5CP1b33kfjDzd5doT/P9QD+eWI8PkO4of//1oPR1jk0fUPNv8NdvnR8B9Y+dHwp6n8RzT5v/ao/H/xaOH3HTV8gfUDSvgjl+8g+S9o+pHrB5D56Hzk+gW9/iGn/kLjAwA0Mwi28cYsaAAAAABJRU5ErkJggg==','qrv23'=>'iVBORw0KGgoAAAANSUhEUgAAAHUAAAB1AQMAAABKyjz/AAAABlBMVEUAAAD///+l2Z/dAAAAoUlEQVR4nGP4jwJ+MJDK/yCPxHWoYPh+H8H9G1/B8CUewf8TiMa/COGzQxFIHqS/HIr+3a9g+CAaigBA80H6YPJg99xH6Mfq3vto/FF5VD47UvixA/nlSOFbDuSH/0dCWOTR9Q82/w12+dHwH1j50fCnqfyPeFT+H3tU/sd4tPD7jhq+oPoFOfyR6weQ/Bc0/V/Q7EPnI9dPGPUXGfUfGh8AsZFlK+3jnj0AAAAASUVORK5CYII=','qrv24'=>'iVBORw0KGgoAAAANSUhEUgAAAHkAAAB5AQMAAAAnNBwKAAAABlBMVEUAAAD///+l2Z/dAAAAvElEQVR4nGP4jwoaGMgQ+CCPxP3C3sDw/T6SwN/vDQxf4pEEzoqjCRyFCPwBGsP+//9BoBZxsBl/gcaU//9/F6gFaMYH0VAECGEHuwOhAuyw+0hmYHf6fXSBEa6CHSnEPtQDBcqRwvQ7SCD8/9/4/0Dy/9X//79iVYFhxqD17XBSMRpzQ1XFaMwNShV/5qML7EcT+HYfPdS/o8ULsCZEjTmUWgykAqWe+1CPVhOCbMEQQKlNMepbMutsdAEA/4f4zbKz0CQAAAAASUVORK5CYII=','qrv25'=>'iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9AQMAAAC1Tv5mAAAABlBMVEUAAAD///+l2Z/dAAAAu0lEQVR4nO2VsQ3CMBBF3WUCaq/CChQopceIu4wGjJCCEt0KLogMkq2Pk0jofLgKTUB256en09m/+Ar5eagVwGl2jWerPHHBWHU37B4OAmBYwAVwPYJGHJYZN8D3iIRAVrndkZ29nfd4G/NixGaUVycJqvG10fBfbxLoeC5dAi1wBcYEDNCWjI8Zm33tPxk1uV81anKbNEYtQDwJ8CT5617kMrVpllzWhJORdeU0I29TFEDeyLKzV/a+BC8ZY3Bb+k3wqAAAAABJRU5ErkJggg==','qrv26'=>'iVBORw0KGgoAAAANSUhEUgAAAIEAAACBAQMAAADdbksTAAAABlBMVEUAAAD///+l2Z/dAAAAt0lEQVR4nGP4jwYaGMgT+SCPzD/D3sDw/T6yyNXvDQxf4pFFnoqjixyFirD///+hHky9FYeYU/7///d6MHUWaM4H0VAkEMIOcQ9CDdiF95HNweGL+xgio2pIVcOOHM4f6oEi5chx8R0kEv4fhL7WQymsajDNGfx+H8lqRuN9ZKoZjfdhp+bTfHSRL/boIj/uY8TXd/Q4BbUBUOMdte4GqUGt3z/Uo7cBwLZjiKC2JTDbG+S3WzBEAPCk5VV3owwNAAAAAElFTkSuQmCC','qrv27'=>'iVBORw0KGgoAAAANSUhEUgAAAIUAAACFAQMAAABPFKl/AAAABlBMVEUAAAD///+l2Z/dAAAAtklEQVR4nGP4jwZ+MJAn8kEemf/PoYLh+31kkb/3Kxi+xKOouYgu8h8q8qH+/392MPXnIsSc70CRcjD1B2jOB9FQZAC0C6QZoQbswvvI5uDwxX0MkVE1A6WGHSW+2IEi5ShxWg4UCf///yuQCaOwqsE0Z2D9NaoGv5rReB+Zakbjfdip+S2PLvLVHl0EVJujxdd39DgFtSVQ4x21DQBSg9pOAJmD1pb4j00EtU2C2W4hv/2DIQIAYitlc7K3dssAAAAASUVORK5CYII=','qrv28'=>'iVBORw0KGgoAAAANSUhEUgAAAIkAAACJAQMAAAAi6omKAAAABlBMVEUAAAD///+l2Z/dAAAAsUlEQVR4nGP4jw4aGMgW+iCPIvCGvYHh+30UobPfGxi+xKMI/RXHEHoKEfpQj0BfxcFmfa9HIJBZH0RDkUEIO9hdyKrATr2PYhYuD93HFBqhqthRwutDPVCoHCVUv4OEwv9/rUdG2FVhMWtQ+HEkqBqNx+GhajQeh4eq0Xgc5Kp+z8cQ+rQfQ+hfPGbYf8eIIWBrCD0e0VowIFVfMM1Caw2BbMQihNaywtL+oqgthykEAL6K28xpVI6wAAAAAElFTkSuQmCC','qrv29'=>'iVBORw0KGgoAAAANSUhEUgAAAI0AAACNAQMAAACwkGvmAAAABlBMVEUAAAD///+l2Z/dAAAArUlEQVR4nGP4jw5+MJAt9EEeReCPQwXD9/uoQvEVDF/iUfUFYgj9vQgRYkegv4EQs8oR6M/9CoYPoqEoAGgjyAAkVWCn3kcxC5eH7mMKjaqiWBU7atizA4XKUWOoHCgU/h8VYVeFxaxB4ceRoGo0HoeHqtF4HB6qRuNxkKv6JI8h9Hk/htDHeMyw/44RQ6CWFVo8orWGQKq+YJqF3tj6j1UIrZWGpS1HUbsQUwgAuBtGI/5sXtsAAAAASUVORK5CYII=','qrv3'=>'iVBORw0KGgoAAAANSUhEUgAAACUAAAAlAQMAAAD/ULJAAAAABlBMVEUAAAD///+l2Z/dAAAAT0lEQVR4nGP4DwQ/GDDJD/L/D1QwfL///34Fw5f4/xdRSYj4B9FQhwqYrvtIJlDGZgeS3/+Xg90Q/gNkF5ANtJcdTP6Hkd/vQ92J1f1gEgCIBqRbO+8EJQAAAABJRU5ErkJggg==','qrv30'=>'iVBORw0KGgoAAAANSUhEUgAAAJEAAACRAQMAAAD5FshgAAAABlBMVEUAAAD///+l2Z/dAAAAyElEQVR4nO2WMQ4CIRBF6TiBsfQoXkJjucfYEm7iWTzAdm5pqLancENiNN9htxoGqm2MGSp4+fkMwxTfQCxvtrB44ORuvUmBsyl58+w4G/eSTSuLDm9ytcBtZeSXHD7k2gMPYCC/uDuzdbJLfUy31By4X/NtocJUZ6htrH/REet5n1NmF8zEOtAGI+jQ0NX8fum9qtM5UF1bp3OgOp2Dv9fNV8leR8liV/m3JP+XcqKYgzLXZV2Z/6KTOTHfW2Nl7qzl0615t8K+i+b7JmwH5H8AAAAASUVORK5CYII=','qrv31'=>'iVBORw0KGgoAAAANSUhEUgAAAJUAAACVAQMAAABrbCoMAAAABlBMVEUAAAD///+l2Z/dAAAAxElEQVR4nO2WMQ4CIRBF6TiB9R5Fr2BhLDkGdHs1PYKFpeEKFBpMZP0CNjI7VGthzJBteHnMQmaKrzBbd7WEhYGgg1PRt+jpnbqalk2nPtPAEQgj0oC0fdezwAWIIyaPlOuF1a5dG1fv9+nVO/u2XvdtnmHifd/TpB86M0v6ZjPbo3xn4JaZyZuOx9X7pfeKJ3MgXt+TORBP5uDvvRq9CHusmbOG6Vuc97fkTjoHNCcWj+bJUo/mzvJfjtEcy+bdhfmZYS99hoUndLveOgAAAABJRU5ErkJggg==','qrv32'=>'iVBORw0KGgoAAAANSUhEUgAAAJkAAACZAQMAAAAGkgr5AAAABlBMVEUAAAD///+l2Z/dAAAA0ElEQVR4nO2XMQ7CMAxFs+UEqCOXAjH2GB2Tm3AWBm4AY9UTIGVoZSFRGbtlqeNWlWAA4SxNv54cR/7Dj8N8RfemmLZCuvjooBHiDaJrSyGeC0XsXmIK+KDSHvGE2BdjTQjY06dCrImkmmmzn66dH/uckEPzjag5f03ZvJG/THox9xRIrIRDgMUDeYrEEnl35Z85Uq35hXc3cg1pDjFymTSHGLlMmkP+kuw08q6R7VGbJihz50SdOSRLv0xmOTkFJVEPp2tiltLVPP+BN4ImPgG/xid8Jp8mGwAAAABJRU5ErkJggg==','qrv33'=>'iVBORw0KGgoAAAANSUhEUgAAAJ0AAACdAQMAAACU6OiVAAAABlBMVEUAAAD///+l2Z/dAAAAvklEQVR4nGP4jwl+MFAo+EEeXexABcP3+2hi/+IrGL7Eown+uYhHkP3//w/1MOrvRYiZ5f//f6+HU0AzP4iGogGHCrA7UVWCHH8fzUzc3kR3/KhKeqlkR48jdqBgOXpslgMFw/+D0Nd6BIVLJVYzB6HfR1VSV+VoWhpVSS2Vo2lpVCW1VI6mpVGVeFX+icci+AObyt/zscX7dywpBNRKx0hLmC1qoEqMtjfITIxWOsh2rIIYLX/sfQTK+x3YBAGoBqgEbsZQeAAAAABJRU5ErkJggg==','qrv34'=>'iVBORw0KGgoAAAANSUhEUgAAAKEAAAChAQMAAACVn031AAAABlBMVEUAAAD///+l2Z/dAAAAwUlEQVR4nO2XQQoCMQxFu+sJxKWXUlx6jFm2N/E0nmMuoBDBIaCLmqgMmn5dqBSRdFP6eIQG/uaHAk4On1OaWbaNOXBv6YZzOKws3U0RHW6UUilxvNTVuSzPbrwGmUuThTnzeP3vo3vZordzX2xcbeHu37nR5oGS0M5mh5UuJW/yvL+eunhu293c/R3Xc+ZuC9dz5m4L13Pm7pvuCbr7hOhxDfPAKDvaReqc1Z1B3bpfUEJdRP+Aad1xcB/6Ts+C9Ax4YVFegvBcpQAAAABJRU5ErkJggg==','qrv35'=>'iVBORw0KGgoAAAANSUhEUgAAAKUAAAClAQMAAAAH5a+ZAAAABlBMVEUAAAD///+l2Z/dAAAAuklEQVR4nO2XsQ0CMQxF3WUCalZhBQpEmTGSjlGYiQmyQnQCHcWJEIvmzv9DAxII2XL19PUVx26+NFJXeZ/WtWXTJstYgJYs52jpbcvodHrQsGil6puWHbPU1c5Wf4M6Ga1OUazvi4lhCtd+TRtgb6HTBDtOne4b9FMt9/3df3Bt83twLVC/B9fOqd+Da+fU7+HvtUNktB4YvRzp3ka2Y804eA8ki3Qt5hb1xYyjb+AUsxPPWZ/Jb5TeAe6Sr8y1YXdqAAAAAElFTkSuQmCC','qrv36'=>'iVBORw0KGgoAAAANSUhEUgAAAKkAAACpAQMAAABqG49sAAAABlBMVEUAAAD///+l2Z/dAAAAz0lEQVR4nO2XMQ7CMAxFs+UEiJFLgRh7jI7J1dhZO1a9QoSovICM3W71T8UQweJMydeTE8d/+YHRyqGJXE5GvMccaDLySDk8OyPPRygPq3xjLolfcklkPSgttUdmSvyWS3rWwyy1y+GyXee4vHtLL+1MpvZe87Ydp6P5wZJE7s1/k8pXHmROIncs+/VQpyu1/9Cl07+l3VVOt6fdVU63p91VTren3VVOf0E/ME2YloHDyRP0iaQ65CqQvJQGOa0kmOr0JRUZJMZKvmyWXbH8AYzzlgWNo1a1AAAAAElFTkSuQmCC','qrv37'=>'iVBORw0KGgoAAAANSUhEUgAAAK0AAACtAQMAAAD4YW0AAAAABlBMVEUAAAD///+l2Z/dAAAA00lEQVR4nO2XOw7CMBBE3fkE1LkKV6BAlD6G0/lsHIGCEuUKlvgYCZxhnXTsOqIw0KyLSB49TbLZacZAOnfTRI4dE8d1b9LA5Ox6c3Hc4yDK4yw/yd4CeyCGcsmbyTuTvQdOQArThbzjassOfUl58ztdxhmY99LwfBylv0lbvh1Lsue79CTvKFygJ47ANcyXOl3x/sOUSv+W1lQp3Z7WVCndntZUKd2e1lQp/QH9cKJ8k+lzJ28+iTmhxiilSmp1RAsdsHhLRRJVWWijle669AcbyC+f/Cip4QSdmwAAAABJRU5ErkJggg==','qrv38'=>'iVBORw0KGgoAAAANSUhEUgAAALEAAACxAQMAAACx586GAAAABlBMVEUAAAD///+l2Z/dAAAA0klEQVR4nO2XMQrDMAxFvfkEJWMu1dIxx8hoX62H6BgydTclwUuKKjmlQyV7aXAgyFP0eCiW+YsMiMebrXhoOZ2sN3HkfI7eTB3nQyPz+4ffAIKDBf9kU/Fo1v4DQHTwwq8+FdQ/nC7snO16/18/zTXy/sV3EOZS/0C+5XkIDnnP8xOJXzGnGD3kHXyLgp/rv9e86u/ra97Ur+lr3tSv6Wve1K/pa97U/8Nfcr6T+bPN5CHK+aF9WcqbtM+SL+2/wcn7Mt0nx6V9nLi0vxffcxv+Bl1q8DHjpSZ5AAAAAElFTkSuQmCC','qrv39'=>'iVBORw0KGgoAAAANSUhEUgAAALUAAAC1AQMAAAAjnSzqAAAABlBMVEUAAAD///+l2Z/dAAAAy0lEQVR4nO2YsQ3DIBBF6ZggtVfJCi4il4wBnVfLCpmAFShikSL25XDliA9FZNlEOpqzvp5O3PGbb0XwvNReeuhydb47FT3AvVNPA/ge68tj1cNIpGlT3v3aP7JgaVuMU+Fyy8/VpfvnfJrL5/2re0BzCf87r8H+NesWvJdlfaCJvwb6KhW+1P+seYX/L178KXzLvPhT+JZ58afwLfPiT+EP5CeD9WXE+twV/BOx3ziPQ3/CvMw8ytepP8rj6T4lHeZ9wv8HqvvcR/8AS6x3b+hbFC8AAAAASUVORK5CYII=','qrv4'=>'iVBORw0KGgoAAAANSUhEUgAAACkAAAApAQMAAACSrpK1AAAABlBMVEUAAAD///+l2Z/dAAAAVklEQVR4nGP4DwINDFipD/L//7A3MHy////v9waGL/H//4qjU1C5D6KhIewI7fdRDKMH70M9kPr+/3s92NVf68EuA/GA7vwAoUAqodT3+zD/4fQ7hAIAixfOUiSVhsgAAAAASUVORK5CYII=','qrv40'=>'iVBORw0KGgoAAAANSUhEUgAAALkAAAC5AQMAAABOYwwfAAAABlBMVEUAAAD///+l2Z/dAAAAyklEQVR4nO2YsQrCQAyGb7snkI6+lOLoY3TMvUmfyk3p5B5BORA0Gtuh0j83FfQgRyHQj480139KEHxSWBDwGrw+xhRyD8Ahp3DdA3BqDHAeQRRhmpZHM/RoRTJNi/bg1XZ+NnGYY2Z8BuxBj/KVoAHdqMmI4J8zvUELUpIV7ESfG32XkmH2+OnkbtRueHbdqNXw7LpRq+HZdaNWw7Prxl8Yl84AT8u4d1auspFE3UzA7MKtgRpwz8BkbCb0q0wAtx8K4L6kfLuLgReQZDV0GOMEHgAAAABJRU5ErkJggg==','qrv5'=>'iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtAQMAAAAA1HDZAAAABlBMVEUAAAD///+l2Z/dAAAAVUlEQVR4nGP4DwI/GLBSH+T//z9QwfD9/v//9ysYvsT//38RnYLKfRANDXWogGu/j2LYgPPYgdT3///LIT4K/wF2NZAH8gM7hPoPp77fh/sdV7hAKAAMKvek396FvAAAAABJRU5ErkJggg==','qrv6'=>'iVBORw0KGgoAAAANSUhEUgAAADEAAAAxAQMAAABJUtNfAAAABlBMVEUAAAD///+l2Z/dAAAAWklEQVR4nGP4DwYNDLjoD/L///9hb2D4fv///7/fGxi+xANpcUwaJv9BNDQ0hB3JnPto5g5B/od6IP39///v9ZDw+FoP8S+ID/L/BygNUg+jv99HhB++8IXSABpDKd6XTw/0AAAAAElFTkSuQmCC','qrv7'=>'iVBORw0KGgoAAAANSUhEUgAAADUAAAA1AQMAAADbKDEzAAAABlBMVEUAAAD///+l2Z/dAAAAgUlEQVR4nGP4DwY/GHDRH+SBlEMFw/f7////u1/B8CUeSF+E0oFgmv1PIFi+/D9Q/oNoaGgoUD1QVznYnPv/2VHMvY9mD6V8dhAE0uUgCKTDQRCJD5Onln3xEPpHPYT+Fg81/zvEPmB4ge0HhweQ/wUq/wWqD0Z/v48UvnjCH0oDAEGdRpZ74EV3AAAAAElFTkSuQmCC','qrv8'=>'iVBORw0KGgoAAAANSUhEUgAAADkAAAA5AQMAAAC21hHGAAAABlBMVEUAAAD///+l2Z/dAAAAk0lEQVR4nGP4DwENDHgYH+SB1Bf2Bobv94GMo98bGL7EAxlPxaGMtxDGwf9/xcFq7v6/C1TzQTQ0NDSEHWzOXYiB94FqUK24j2Ep7UTYgbZ/qAcyyoHu+Q5ihP+/+v8righcDe3d83s+lPEDJvLxPsz271D3AEMe4kJwqIJEwOH8oR4a8iBdcMZ3mBXg+CIQpzAGAF5Ci9Zhup/SAAAAAElFTkSuQmCC','qrv9'=>'iVBORw0KGgoAAAANSUhEUgAAAD0AAAA9AQMAAAAkrPOqAAAABlBMVEUAAAD///+l2Z/dAAAAlElEQVR4nGP4DwE/GPAwPsgDqb8HKhi+3wcy/tyvYPgSD2T8uwhl/A0EMz7U/70IVvO9/i9QzQfRUCBwqACZ870ebOB9oBpUK+5jWEpPEXaQe9iBjHKQC8uBjPD/X+v/hyOLwNUMhAs/yUMZP2Ei/+7D3PMd6kJg7EDcDA55kAg4LkBqwLED0gVnfIdZ8UEe3S7cDABarr4ne1P6CQAAAABJRU5ErkJggg==');

    private $counter;

    private $codeword_num;

    private $value;

    private $bits;

    /**
     * Конструктор
     *
     * @param char $ess
     * @param int $size
     * @param string $type
     * @return bool
     */
  public function __construct($ecc='M',$size=10,$type='png')
  {
        $this->setEcc($ecc);
        $this->setSize($size);
        $this->setType($type);
        return true;
  }
    /**
     * Деструктор
     *
     */
  public function __destruct()
  {
    foreach (get_class_vars(__CLASS__) as $k=>$v)
        $this->$k = null;
  }
    /**
     * установить строку для кодирования
     *
     * @param string $str
     * @return bool
     */
  public function setData($str)
  {
    if(!empty($str)){
        $this->data = $str;
        $this->datalength = strlen($str);
        $this->counter=0;
        $this->codeword_num = array();
        $this->value = array();
        $this->bits = array();
        $this->bits[$this->counter]=4;
        return true;
    }
    else
       return $this->showError('введите текст');
  }
    /**
     * Код коррекции ошибок
     *
     * @param char $ecc
     * @return bool
     */
  public function setEcc($ecc)
  {
    if(!empty($ecc) && array_key_exists($ecc,self::$ecc_hash)){
        $this->ecc = self::$ecc_hash[$ecc];
        return true;
    }
    else
       return $this->showError('введите код коррекции ошибок');

  }
    /**
     * Размер
     *
     * @param int $size
     * @return bool
     */
  public function setSize($size)
  {
    if(!empty($size) && $size>0 && $size<50){
        $this->size = $size;
        return false;
    }
    else
        return $this->showError('введите размер');

  }

    /**
     * Формат вывода изображения (png/jpeg)
     *
     * @param string $type
     * @return bool
     */
  public function setType($type)
  {
    if(!empty($type) && ($type=='png' || $type=='jpeg')){
        $this->type = $type;
        return true;
    }
    else
        return $this->showError('введите текст');
  }

    /**
     * Путь к вспомогательным файлам
     *
     * @param string $str
     * @return bool
     */
  public function setPath($str)
  {
    if(!empty($str)){
        $this->path = $str;
        return true;
    }
    else
        return $this->showError('введите путь к файлам данных');

  }

    /**
     * Закодировать и вывести или сохранить изображение
     * при $file==null выводит на экран
     *
     * по ходу функции добавлю комментврии позже;
     * возможно, стоит разбить на несколько отдельных методов
     * по разбивке фразы, поиску соответсвий в dat файлах, выводе кода
     *
     * @param string $str
     * @param string $file
     * @return mixed
     */
  public function draw($str,$file=null)
  {
    $this->setData($str);

    //  определяем метод кодирования,готовим данные
    $codeword_counter=(ereg('[^0-9]',$this->data))?
        ((ereg('[^0-9A-Z \$\*\%\+\-\.\/\:]',$this->data))?
        $this->prepare8bit():$this->prepareAlNum()):$this->prepareNum();

    if (isset($this->bits[$this->counter]) && $this->bits[$this->counter]>0)
        $this->counter++;

    $total_data_bits=0;
    for($i=0;$i<$this->counter;$i++)
        $total_data_bits+=$this->bits[$i];
        // попутно определяем версию
    for($version=1,$i=1+40*$this->ecc;
        $i<=40*(1+$this->ecc);
        $i++,$version++){
        if (self::$data_bits[$i]>=$total_data_bits+$this->codeword_num[$version]){
            $max_data_bits=self::$data_bits[$i];
            break;
        }
    }

    $total_data_bits+=$this->codeword_num[$version];
    $this->bits[$codeword_counter]+=$this->codeword_num[$version];

    $max_codewords_array=array(0,26,44,70,100,134,172,196,242,
    292,346,404,466,532,581,655,733,815,901,991,1085,1156,
    1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,
    2611,2761,2876,3034,3196,3362,3532,3706);

    $max_codewords=$max_codewords_array[$version];
    $max_modules_1side=17+($version <<2);

    $matrix_remain_bit=array(0,0,7,7,7,7,7,0,0,0,0,0,0,0,
    3,3,3,3,3,3,3,4,4,4,4,4,4,4,3,3,3,3,3,3,3,0,0,0,0,0,0);

    // опрделяем способ коррекции ошибок

    $byte_num=$matrix_remain_bit[$version]+($max_codewords << 3);
    $filename=$this->path.'/qrv'.$version.'_'.$this->ecc.'.dat';
    if(!file_exists($filename))
        $this->showError('файл «'.$filename.'» не существует');
    $fp1 = fopen ($filename, 'rb');
        $matx=fread($fp1,$byte_num);
        $maty=fread($fp1,$byte_num);
        $masks=fread($fp1,$byte_num);
        $fi_x=fread($fp1,15);
        $fi_y=fread($fp1,15);
        $rs_ecc_codewords=ord(fread($fp1,1));
        $rso=fread($fp1,128);
    fclose($fp1);

    $matrix_x_array=unpack('C*',$matx);
    $matrix_y_array=unpack('C*',$maty);
    $mask_array=unpack('C*',$masks);

    $rs_block_order=unpack('C*',$rso);

    $format_x2=unpack('C*',$fi_x);
    $format_y2=unpack('C*',$fi_y);

    $format_x1=array(0,1,2,3,4,5,7,8,8,8,8,8,8,8,8);
    $format_y1=array(8,8,8,8,8,8,8,8,7,5,4,3,2,1,0);

    $max_data_codewords=($max_data_bits >>3);

    $filename = $this->path.'/rsc'.$rs_ecc_codewords.'.dat';
    if(!file_exists($filename))
        $this->showError('файл «'.$filename.'» не существует');

    $fp0 = fopen ($filename, 'rb');
       for($i=0;$i<256;$i++)
        $rs_cal_table_array[$i]=fread ($fp0,$rs_ecc_codewords);
    fclose ($fp0);

    if ($total_data_bits<=$max_data_bits-4){
        $this->value[$this->counter]=0;
        $this->bits[$this->counter]=4;
    } else {
        if ($total_data_bits<$max_data_bits){
    	    $this->value[$this->counter]=0;
            $this->bits[$this->counter]=$max_data_bits-$total_data_bits;
        } else
            if ($total_data_bits>$max_data_bits)
                    $this->showError('переполнение');
    }

    $codewords_counter=0;
    $codewords[0]=0;
    $remaining_bits=8;

    for($i=0;$i<=$this->counter;$i++) {
        $buffer=$this->value[$i];
        $buffer_bits=$this->bits[$i];

        $flag=1;
        while ($flag) {
            if ($remaining_bits>$buffer_bits){
                $codewords[$codewords_counter]=(($codewords[$codewords_counter]<<$buffer_bits) | $buffer);
                $remaining_bits-=$buffer_bits;
                $flag=0;
            } else {
                $buffer_bits-=$remaining_bits;
                $codewords[$codewords_counter]= (($codewords[$codewords_counter] << $remaining_bits) | ($buffer >> $buffer_bits));

                if ($buffer_bits==0)
                    $flag=0;
                else {
                    $buffer= ($buffer & ((1 << $buffer_bits)-1) );
                    $flag=1;
                }

                $codewords_counter++;
                if ($codewords_counter<$max_data_codewords-1)
                    $codewords[$codewords_counter]=0;

                $remaining_bits=8;
            }
        }
    }
    if ($remaining_bits!=8)
        $codewords[$codewords_counter]= $codewords[$codewords_counter] << $remaining_bits;
    else
        $codewords_counter--;

    if ($codewords_counter<$max_data_codewords-1){
        $flag=1;
        while ($codewords_counter<$max_data_codewords-1){
            $codewords_counter++;
            $codewords[$codewords_counter]=$flag?236:17;
            $flag=!$flag;
        }
    }

    $block_number=0;
    $rs_temp[0]='';

    for($i=0,$j=0;$i<$max_data_codewords;$i++){
        $rs_temp[$block_number].=chr($codewords[$i]);
        $j++;

        if ($j>=$rs_block_order[$block_number+1]-$rs_ecc_codewords){
            $j=0;
            $block_number++;
            $rs_temp[$block_number]='';
        }
    }

    $count=count($rs_block_order);
    for ($i=0;$i<$count;$i++){

        $rs_codewords=$rs_block_order[$i+1];
        $rs_data_codewords=$rs_codewords-$rs_ecc_codewords;

        $rstemp=$rs_temp[$i].str_repeat(chr(0),$rs_ecc_codewords);
        $padding_data=str_repeat(chr(0),$rs_data_codewords);


        for($j=$rs_data_codewords;$j>0;$j--){
            $first=ord(substr($rstemp,0,1));

            if ($first){
                $left_chr=substr($rstemp,1);
                $cal=$rs_cal_table_array[$first].$padding_data;
                $rstemp=$left_chr ^ $cal;
            } else {
                $rstemp=substr($rstemp,1);
            }
        }

        $codewords=array_merge($codewords,unpack('C*',$rstemp));
    }

    $matrix_content=array_fill(0,$max_modules_1side,array_fill(0,$max_modules_1side,0));

    for($i=0;$i<$max_codewords;$i++){
        $codeword_i=$codewords[$i];

        for($j=8;$j>=1;$j--){
            $codeword_bits_number=($i << 3) +  $j;
            $matrix_content[$matrix_x_array[$codeword_bits_number]][$matrix_y_array[$codeword_bits_number]]=
            ((255*($codeword_i & 1)) ^ $mask_array[$codeword_bits_number]);
            $codeword_i= $codeword_i >> 1;
        }
    }

    $matrix_remain=$matrix_remain_bit[$version];
    while ($matrix_remain){
        $remain_bit_temp = $matrix_remain + ( $max_codewords <<3);
        $matrix_content[ $matrix_x_array[$remain_bit_temp] ][ $matrix_y_array[$remain_bit_temp] ]=
        ( 255 ^ $mask_array[$remain_bit_temp]);
        $matrix_remain--;
    }

    $min_demerit_score=0;
        $hor_master='';
        $ver_master='';

        for($k=0;$k<$max_modules_1side;$k++)
            for($l=0;$l<$max_modules_1side;$l++){
                $hor_master .= chr($matrix_content[$l][$k]);
                $ver_master .= chr($matrix_content[$k][$l]);
            }


    $all_matrix=$max_modules_1side * $max_modules_1side;
    for($i=0;$i<8;$i++){
        $demerit_n1=0;
        $ptn_temp=array();
        $bit= 1<< $i;
        $bit_r=(~$bit)&255;
        $bit_mask=str_repeat(chr($bit),$all_matrix);
        $hor = $hor_master & $bit_mask;
        $ver = $ver_master & $bit_mask;

        $ver_shift1=$ver.str_repeat(chr(170),$max_modules_1side);
        $ver_shift2=str_repeat(chr(170),$max_modules_1side).$ver;
        $ver_shift1_0=$ver.str_repeat(chr(0),$max_modules_1side);
        $ver_shift2_0=str_repeat(chr(0),$max_modules_1side).$ver;
        $ver_or=chunk_split(~($ver_shift1 | $ver_shift2),$max_modules_1side,chr(170));
        $ver_and=chunk_split(~($ver_shift1_0 & $ver_shift2_0),$max_modules_1side,chr(170));

        $hor=chunk_split(~$hor,$max_modules_1side,chr(170));
        $ver=chunk_split(~$ver,$max_modules_1side,chr(170));
        $hor=$hor.chr(170).$ver;

       $demerit_n3=substr_count($hor,chr($bit_r).chr(255).chr($bit_r).chr($bit_r).chr($bit_r).chr(255).chr($bit_r))*40;
       $demerit_n4=floor(abs(( (100* (substr_count($ver,chr($bit_r))/($byte_num)) )-50)/5))*10;

       $demerit_n2=0;
       preg_match_all('/'.chr($bit_r).chr($bit_r).'+/',$ver_and,$ptn_temp);
       foreach($ptn_temp[0] as $str_temp){
           $demerit_n2+=(strlen($str_temp)-1);
       }
       $ptn_temp=array();
       preg_match_all('/'.chr(255).chr(255).'+/',$ver_or,$ptn_temp);
       foreach($ptn_temp[0] as $str_temp){
           $demerit_n2+=(strlen($str_temp)-1);
       }
       $demerit_n2*=3;

       $ptn_temp=array();

       preg_match_all('/'.str_repeat(chr(255),5).'+|'.str_repeat(chr($bit_r),5).'+/',$hor,$ptn_temp);
       foreach($ptn_temp[0] as $str_temp){
           $demerit_n1+=(strlen($str_temp)-2);
       }

       $demerit_score=$demerit_n1+$demerit_n2+$demerit_n3+$demerit_n4;

       if ($demerit_score<=$min_demerit_score || !$i){
            $mask_number=$i;
            $min_demerit_score=$demerit_score;
       }
    }

    $mask_content=1 << $mask_number;

    $format_val=(($this->ecc << 3) | $mask_number);


    for($i=0;$i<15;$i++){
        $content=substr(self::$format_inf[$format_val],$i,1);
        $matrix_content[$format_x1[$i]][$format_y1[$i]]=$content * 255;
        $matrix_content[$format_x2[$i+1]][$format_y2[$i+1]]=$content * 255;
    }

    $mib=$max_modules_1side+8;
    $image_size=$mib*$this->size;
    if ($image_size>1480)
      $this->showError('слишком большой размер изображения');

    $im =imagecreate($image_size,$image_size);

    $base_image = imagecreatefromstring(base64_decode($this->patterns['qrv'.$version]));

    $color=imagecolorallocate($base_image,0,0,0);


    $mxe=4+$max_modules_1side;

    for($ii=0,$i=4;$i<$mxe;$i++,$ii++){
        for($j=4,$jj=0;$j<$mxe;$j++,$jj++){
            if ($matrix_content[$ii][$jj] & $mask_content)
                imagesetpixel($base_image,$i,$j,$color);
        }
    }


    imagecopyresized($im,$base_image,0,0,0,0,$image_size,$image_size,$mib,$mib);

    $function = 'image'.$this->type;

    if(is_null($file))header('Content-type: image/'.$this->type);
    $function($im,$file);


    imagedestroy($base_image);
    imagedestroy($im);

}

    /**
     * строка - 8-ми битная кодировка
     *
     * @return int
     */
    private function prepare8bit()
    {
        $this->codeword_num=array(0,0,0,0,0,0,0,0,0,0,
                    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
                    8,8,8,8,8,8,8,8,8,8,8,8,8,8);

        $this->value[$this->counter]=4;
        $this->value[++$this->counter]=$this->datalength;

        $this->bits[$this->counter]=8;
        $codeword_counter=$this->counter;

        $this->counter++;
        for($i=0;$i<$this->datalength;$i++){
            $this->value[$this->counter]=ord(substr($this->data,$i,1));
            $this->bits[$this->counter]=8;
            $this->counter++;
        }
        return $codeword_counter;
    }
    /**
     * строка - буквы и числа
     *
     * @return int
     */
    private function prepareAlNum()
    {
        $this->codeword_num=array(0,0,0,0,0,0,0,0,0,0,
                    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
                    4,4,4,4,4,4,4,4,4,4,4,4,4,4);

        $this->value[$this->counter]=2;
        $this->value[++$this->counter]=$this->datalength;
        $this->bits[$this->counter]=9;
        $codeword_counter=$this->counter;

        $this->counter++;
        for($i=0;$i<$this->datalength;$i++){
            if (($i %2)==0){
                $this->value[$this->counter]= self::$alphanumeric_hash[substr($this->data,$i,1)];
                $this->bits[$this->counter]=6;
            } else {
                $this->value[$this->counter]= $this->value[$this->counter]*45+ self::$alphanumeric_hash[substr($this->data,$i,1)];
                $this->bits[$this->counter]=11;
                $this->counter++;
            }
        }
        return $codeword_counter;
    }

    /**
     * строка - числа
     *
     * @return int
     */
    private function prepareNum()
    {
        $this->codeword_num=array(0,0,0,0,0,0,0,0,0,0,
                    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
                    4,4,4,4,4,4,4,4,4,4,4,4,4,4);

        $this->value[$this->counter]=1;
        $this->value[++$this->counter]=$this->datalength;
        $this->bits[$this->counter]=10;
        $codeword_counter=$this->counter;

        $this->counter++;
        for($i=0;$i<$this->datalength;$i++){
            if (($i % 3)==0){
                $this->value[$this->counter]=substr($this->data,$i,1);
                $this->bits[$this->counter]=4;
            } else {
                 $this->value[$this->counter]=$this->value[$this->counter]*10+substr($this->data,$i,1);
             if (($i % 3)==1){
                 $this->bits[$this->counter]=7;
             } else {
                 $this->bits[$this->counter]=10;
                 $this->counter++;
             }
            }
        }
        return $codeword_counter;
    }

    /**
     * Вывести сообщение с ошибкой
     *
     * @param string $str
     * @return bool
     */
  private function showError($str)
  {
    if(!empty($str))
        die('<b>Ошибка</b>: '.$str);
    return false;
  }
}
?>