Архивная версия сайта e-luge.net. Последняя запись сделана 1 марта 2011 года.
Город съехавших крыш
02-02-2009 01:59   |  Метки: php, qr-код

Хитрые японцы уже порядка 10 лет использют в повседневной жизни QR-коды. В двух словах, это — закодированное в двухмерной картинке сообщение (адрес, телефон, заметка и т.д.). Если к этому добавить, что в картинку можно вместить 4000 символов и порядка 30% информации для восстановления, то становится понятно, почему этот формат получил такое распространение.

Раз есть технология, то почему бы её не использовать? Ну, или хотя бы не посмотреть как оно работает?

Google-API использовать не хотелось.

  1. <img src="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=http://www.e-luge.net/" />
Это, конечно, просто и быстро, но совсем не интересно.

Будем копать дальше.

http://www.swetake.com/qr/qr1_en.html — скрипт, который практически без изменений используется в модулях друпала и вордпресса. Вот это уже интересно.

Часа где-то через полтора получилось вот это:

QR.class.php:

  1. <?php
  2. /**
  3.  * @package Генерация QR-кода
  4.  *
  5.  * @author Павел Новицкий <lugebox@gmail.com>
  6.  * @link http://www.e-luge.net/
  7.  */
  8. class QR{
  9. /**
  10.   * пользовательский текст
  11.   *
  12.   * @var string
  13.   */
  14. private $data;
  15.  
  16. /**
  17.   * размер введённых даных
  18.   *
  19.   * @var int
  20.   */
  21. private $datalength;
  22.  
  23. /**
  24.   * код коррекции ошибок
  25.   * (L, M, Q, H )
  26.   * по умолчанию M
  27.   *
  28.   * @var char
  29.   */
  30. private $ecc;
  31.  
  32. /**
  33.   * размер изображения
  34.   * (1-50)
  35.   * по умолчанию 10
  36.   *
  37.   * @var int
  38.   */
  39. private $size;
  40.  
  41. /**
  42.   * тип изображения
  43.   * (jpeg, png)
  44.   * по умолчанию png
  45.   *
  46.   * @var int
  47.   */
  48. private $type;
  49.  
  50. /**
  51.   * путь к файлам данных QR кодов
  52.   *
  53.   * @var string
  54.   */
  55. private $path;
  56.  
  57. /**
  58.   * кодирование кодов коррекции
  59.   *
  60.   * @var array
  61.   */
  62. private static $ecc_hash=array('L'=>'1','l'=>'1','M'=>'0','m'=>'0','Q'=>'3',
  63. 'q'=>'3','H'=>'2','h'=>'2');
  64.  
  65. /**
  66.   * кодирование символов
  67.   *
  68.   * @var array
  69.   */
  70. private static $alphanumeric_hash=array('0'=>0,'1'=>1,'2'=>2,'3'=>3,'4'=>4,
  71. '5'=>5,'6'=>6,'7'=>7,'8'=>8,'9'=>9,'A'=>10,'B'=>11,'C'=>12,'D'=>13,'E'=>14,
  72. 'F'=>15,'G'=>16,'H'=>17,'I'=>18,'J'=>19,'K'=>20,'L'=>21,'M'=>22,'N'=>23,
  73. 'O'=>24,'P'=>25,'Q'=>26,'R'=>27,'S'=>28,'T'=>29,'U'=>30,'V'=>31,
  74. 'W'=>32,'X'=>33,'Y'=>34,'Z'=>35,' '=>36,'$'=>37,'%'=>38,'*'=>39,
  75. '+'=>40,'-'=>41,'.'=>42,'/'=>43,':'=>44);
  76.  
  77. /**
  78.   * битовое положение в файлам данных QR кодов
  79.   *
  80.   * @array
  81.   */
  82. private static $data_bits=array(
  83. 0,128,224,352,512,688,864,992,1232,1456,1728,
  84. 2032,2320,2672,2920,3320,3624,4056,4504,5016,5352,
  85. 5712,6256,6880,7312,8000,8496,9024,9544,10136,10984,
  86. 11640,12328,13048,13800,14496,15312,15936,16816,17728,18672,
  87.  
  88. 152,272,440,640,864,1088,1248,1552,1856,2192,
  89. 2592,2960,3424,3688,4184,4712,5176,5768,6360,6888,
  90. 7456,8048,8752,9392,10208,10960,11744,12248,13048,13880,
  91. 14744,15640,16568,17528,18448,19472,20528,21616,22496,23648,
  92.  
  93. 72,128,208,288,368,480,528,688,800,976,
  94. 1120,1264,1440,1576,1784,2024,2264,2504,2728,3080,
  95. 3248,3536,3712,4112,4304,4768,5024,5288,5608,5960,
  96. 6344,6760,7208,7688,7888,8432,8768,9136,9776,10208,
  97.  
  98. 104,176,272,384,496,608,704,880,1056,1232,
  99. 1440,1648,1952,2088,2360,2600,2936,3176,3560,3880,
  100. 4096,4544,4912,5312,5744,6032,6464,6968,7288,7880,
  101. 8264,8920,9368,9848,10288,10832,11408,12016,12656,13328
  102. );
  103.  
  104. /*
  105.   * побитовая разбивка
  106.   */
  107. private static $format_inf=array('101010000010010','101000100100101',
  108. '101111001111100','101101101001011','100010111111001','100000011001110',
  109. '100111110010111','100101010100000','111011111000100','111001011110011',
  110. '111110110101010','111100010011101','110011000101111','110001100011000',
  111. '110110001000001','110100101110110','001011010001001','001001110111110',
  112. '001110011100111','001100111010000','000011101100010','000001001010101',
  113. '000110100001100','000100000111011','011010101011111','011000001101000',
  114. '011111100110001','011101000000110','010010010110100','010000110000011',
  115. '010111011011010','010101111101101');
  116.  
  117. 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==');
  118.  
  119. private $counter;
  120.  
  121. private $codeword_num;
  122.  
  123. private $value;
  124.  
  125. private $bits;
  126.  
  127. /**
  128.   * Конструктор
  129.   *
  130.   * @param char $ess
  131.   * @param int $size
  132.   * @param string $type
  133.   * @return bool
  134.   */
  135. public function __construct($ecc='M',$size=10,$type='png')
  136. {
  137. $this->setEcc($ecc);
  138. $this->setSize($size);
  139. $this->setType($type);
  140. return true;
  141. }
  142. /**
  143.   * Деструктор
  144.   *
  145.   */
  146. public function __destruct()
  147. {
  148. foreach (get_class_vars(__CLASS__) as $k=>$v)
  149. $this->$k = null;
  150. }
  151. /**
  152.   * установить строку для кодирования
  153.   *
  154.   * @param string $str
  155.   * @return bool
  156.   */
  157. public function setData($str)
  158. {
  159. if(!empty($str)){
  160. $this->data = $str;
  161. $this->datalength = strlen($str);
  162. $this->counter=0;
  163. $this->codeword_num = array();
  164. $this->value = array();
  165. $this->bits = array();
  166. $this->bits[$this->counter]=4;
  167. return true;
  168. }
  169. else
  170. return $this->showError('введите текст');
  171. }
  172. /**
  173.   * Код коррекции ошибок
  174.   *
  175.   * @param char $ecc
  176.   * @return bool
  177.   */
  178. public function setEcc($ecc)
  179. {
  180. if(!empty($ecc) && array_key_exists($ecc,self::$ecc_hash)){
  181. $this->ecc = self::$ecc_hash[$ecc];
  182. return true;
  183. }
  184. else
  185. return $this->showError('введите код коррекции ошибок');
  186.  
  187. }
  188. /**
  189.   * Размер
  190.   *
  191.   * @param int $size
  192.   * @return bool
  193.   */
  194. public function setSize($size)
  195. {
  196. if(!empty($size) && $size>0 && $size<50){
  197. $this->size = $size;
  198. return false;
  199. }
  200. else
  201. return $this->showError('введите размер');
  202.  
  203. }
  204.  
  205. /**
  206.   * Формат вывода изображения (png/jpeg)
  207.   *
  208.   * @param string $type
  209.   * @return bool
  210.   */
  211. public function setType($type)
  212. {
  213. if(!empty($type) && ($type=='png' || $type=='jpeg')){
  214. $this->type = $type;
  215. return true;
  216. }
  217. else
  218. return $this->showError('введите текст');
  219. }
  220.  
  221. /**
  222.   * Путь к вспомогательным файлам
  223.   *
  224.   * @param string $str
  225.   * @return bool
  226.   */
  227. public function setPath($str)
  228. {
  229. if(!empty($str)){
  230. $this->path = $str;
  231. return true;
  232. }
  233. else
  234. return $this->showError('введите путь к файлам данных');
  235.  
  236. }
  237.  
  238. /**
  239.   * Закодировать и вывести или сохранить изображение
  240.   * при $file==null выводит на экран
  241.   *
  242.   * по ходу функции добавлю комментврии позже;
  243.   * возможно, стоит разбить на несколько отдельных методов
  244.   * по разбивке фразы, поиску соответсвий в dat файлах, выводе кода
  245.   *
  246.   * @param string $str
  247.   * @param string $file
  248.   * @return mixed
  249.   */
  250. public function draw($str,$file=null)
  251. {
  252. $this->setData($str);
  253.  
  254. // определяем метод кодирования,готовим данные
  255. $codeword_counter=(ereg('[^0-9]',$this->data))?
  256. ((ereg('[^0-9A-Z \$\*\%\+\-\.\/\:]',$this->data))?
  257. $this->prepare8bit():$this->prepareAlNum()):$this->prepareNum();
  258.  
  259. if (isset($this->bits[$this->counter]) && $this->bits[$this->counter]>0)
  260. $this->counter++;
  261.  
  262. $total_data_bits=0;
  263. for($i=0;$i<$this->counter;$i++)
  264. $total_data_bits+=$this->bits[$i];
  265. // попутно определяем версию
  266. for($version=1,$i=1+40*$this->ecc;
  267. $i<=40*(1+$this->ecc);
  268. $i++,$version++){
  269. if (self::$data_bits[$i]>=$total_data_bits+$this->codeword_num[$version]){
  270. $max_data_bits=self::$data_bits[$i];
  271. break;
  272. }
  273. }
  274.  
  275. $total_data_bits+=$this->codeword_num[$version];
  276. $this->bits[$codeword_counter]+=$this->codeword_num[$version];
  277.  
  278. $max_codewords_array=array(0,26,44,70,100,134,172,196,242,
  279. 292,346,404,466,532,581,655,733,815,901,991,1085,1156,
  280. 1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,
  281. 2611,2761,2876,3034,3196,3362,3532,3706);
  282.  
  283. $max_codewords=$max_codewords_array[$version];
  284. $max_modules_1side=17+($version <<2);
  285.  
  286. $matrix_remain_bit=array(0,0,7,7,7,7,7,0,0,0,0,0,0,0,
  287. 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);
  288.  
  289. // опрделяем способ коррекции ошибок
  290.  
  291. $byte_num=$matrix_remain_bit[$version]+($max_codewords << 3);
  292. $filename=$this->path.'/qrv'.$version.'_'.$this->ecc.'.dat';
  293. if(!file_exists($filename))
  294. $this->showError('файл «'.$filename.'» не существует');
  295. $fp1 = fopen ($filename, 'rb');
  296. $matx=fread($fp1,$byte_num);
  297. $maty=fread($fp1,$byte_num);
  298. $masks=fread($fp1,$byte_num);
  299. $fi_x=fread($fp1,15);
  300. $fi_y=fread($fp1,15);
  301. $rs_ecc_codewords=ord(fread($fp1,1));
  302. $rso=fread($fp1,128);
  303. fclose($fp1);
  304.  
  305. $matrix_x_array=unpack('C*',$matx);
  306. $matrix_y_array=unpack('C*',$maty);
  307. $mask_array=unpack('C*',$masks);
  308.  
  309. $rs_block_order=unpack('C*',$rso);
  310.  
  311. $format_x2=unpack('C*',$fi_x);
  312. $format_y2=unpack('C*',$fi_y);
  313.  
  314. $format_x1=array(0,1,2,3,4,5,7,8,8,8,8,8,8,8,8);
  315. $format_y1=array(8,8,8,8,8,8,8,8,7,5,4,3,2,1,0);
  316.  
  317. $max_data_codewords=($max_data_bits >>3);
  318.  
  319. $filename = $this->path.'/rsc'.$rs_ecc_codewords.'.dat';
  320. if(!file_exists($filename))
  321. $this->showError('файл «'.$filename.'» не существует');
  322.  
  323. $fp0 = fopen ($filename, 'rb');
  324. for($i=0;$i<256;$i++)
  325. $rs_cal_table_array[$i]=fread ($fp0,$rs_ecc_codewords);
  326. fclose ($fp0);
  327.  
  328. if ($total_data_bits<=$max_data_bits-4){
  329. $this->value[$this->counter]=0;
  330. $this->bits[$this->counter]=4;
  331. } else {
  332. if ($total_data_bits<$max_data_bits){
  333. $this->value[$this->counter]=0;
  334. $this->bits[$this->counter]=$max_data_bits-$total_data_bits;
  335. } else
  336. if ($total_data_bits>$max_data_bits)
  337. $this->showError('переполнение');
  338. }
  339.  
  340. $codewords_counter=0;
  341. $codewords[0]=0;
  342. $remaining_bits=8;
  343.  
  344. for($i=0;$i<=$this->counter;$i++) {
  345. $buffer=$this->value[$i];
  346. $buffer_bits=$this->bits[$i];
  347.  
  348. $flag=1;
  349. while ($flag) {
  350. if ($remaining_bits>$buffer_bits){
  351. $codewords[$codewords_counter]=(($codewords[$codewords_counter]<<$buffer_bits) | $buffer);
  352. $remaining_bits-=$buffer_bits;
  353. $flag=0;
  354. } else {
  355. $buffer_bits-=$remaining_bits;
  356. $codewords[$codewords_counter]= (($codewords[$codewords_counter] << $remaining_bits) | ($buffer >> $buffer_bits));
  357.  
  358. if ($buffer_bits==0)
  359. $flag=0;
  360. else {
  361. $buffer= ($buffer & ((1 << $buffer_bits)-1) );
  362. $flag=1;
  363. }
  364.  
  365. $codewords_counter++;
  366. if ($codewords_counter<$max_data_codewords-1)
  367. $codewords[$codewords_counter]=0;
  368.  
  369. $remaining_bits=8;
  370. }
  371. }
  372. }
  373. if ($remaining_bits!=8)
  374. $codewords[$codewords_counter]= $codewords[$codewords_counter] << $remaining_bits;
  375. else
  376. $codewords_counter--;
  377.  
  378. if ($codewords_counter<$max_data_codewords-1){
  379. $flag=1;
  380. while ($codewords_counter<$max_data_codewords-1){
  381. $codewords_counter++;
  382. $codewords[$codewords_counter]=$flag?236:17;
  383. $flag=!$flag;
  384. }
  385. }
  386.  
  387. $block_number=0;
  388. $rs_temp[0]='';
  389.  
  390. for($i=0,$j=0;$i<$max_data_codewords;$i++){
  391. $rs_temp[$block_number].=chr($codewords[$i]);
  392. $j++;
  393.  
  394. if ($j>=$rs_block_order[$block_number+1]-$rs_ecc_codewords){
  395. $j=0;
  396. $block_number++;
  397. $rs_temp[$block_number]='';
  398. }
  399. }
  400.  
  401. $count=count($rs_block_order);
  402. for ($i=0;$i<$count;$i++){
  403.  
  404. $rs_codewords=$rs_block_order[$i+1];
  405. $rs_data_codewords=$rs_codewords-$rs_ecc_codewords;
  406.  
  407. $rstemp=$rs_temp[$i].str_repeat(chr(0),$rs_ecc_codewords);
  408. $padding_data=str_repeat(chr(0),$rs_data_codewords);
  409.  
  410.  
  411. for($j=$rs_data_codewords;$j>0;$j--){
  412. $first=ord(substr($rstemp,0,1));
  413.  
  414. if ($first){
  415. $left_chr=substr($rstemp,1);
  416. $cal=$rs_cal_table_array[$first].$padding_data;
  417. $rstemp=$left_chr ^ $cal;
  418. } else {
  419. $rstemp=substr($rstemp,1);
  420. }
  421. }
  422.  
  423. $codewords=array_merge($codewords,unpack('C*',$rstemp));
  424. }
  425.  
  426. $matrix_content=array_fill(0,$max_modules_1side,array_fill(0,$max_modules_1side,0));
  427.  
  428. for($i=0;$i<$max_codewords;$i++){
  429. $codeword_i=$codewords[$i];
  430.  
  431. for($j=8;$j>=1;$j--){
  432. $codeword_bits_number=($i << 3) + $j;
  433. $matrix_content[$matrix_x_array[$codeword_bits_number]][$matrix_y_array[$codeword_bits_number]]=
  434. ((255*($codeword_i & 1)) ^ $mask_array[$codeword_bits_number]);
  435. $codeword_i= $codeword_i >> 1;
  436. }
  437. }
  438.  
  439. $matrix_remain=$matrix_remain_bit[$version];
  440. while ($matrix_remain){
  441. $remain_bit_temp = $matrix_remain + ( $max_codewords <<3);
  442. $matrix_content[ $matrix_x_array[$remain_bit_temp] ][ $matrix_y_array[$remain_bit_temp] ]=
  443. ( 255 ^ $mask_array[$remain_bit_temp]);
  444. $matrix_remain--;
  445. }
  446.  
  447. $min_demerit_score=0;
  448. $hor_master='';
  449. $ver_master='';
  450.  
  451. for($k=0;$k<$max_modules_1side;$k++)
  452. for($l=0;$l<$max_modules_1side;$l++){
  453. $hor_master .= chr($matrix_content[$l][$k]);
  454. $ver_master .= chr($matrix_content[$k][$l]);
  455. }
  456.  
  457.  
  458. $all_matrix=$max_modules_1side * $max_modules_1side;
  459. for($i=0;$i<8;$i++){
  460. $demerit_n1=0;
  461. $ptn_temp=array();
  462. $bit= 1<< $i;
  463. $bit_r=(~$bit)&255;
  464. $bit_mask=str_repeat(chr($bit),$all_matrix);
  465. $hor = $hor_master & $bit_mask;
  466. $ver = $ver_master & $bit_mask;
  467.  
  468. $ver_shift1=$ver.str_repeat(chr(170),$max_modules_1side);
  469. $ver_shift2=str_repeat(chr(170),$max_modules_1side).$ver;
  470. $ver_shift1_0=$ver.str_repeat(chr(0),$max_modules_1side);
  471. $ver_shift2_0=str_repeat(chr(0),$max_modules_1side).$ver;
  472. $ver_or=chunk_split(~($ver_shift1 | $ver_shift2),$max_modules_1side,chr(170));
  473. $ver_and=chunk_split(~($ver_shift1_0 & $ver_shift2_0),$max_modules_1side,chr(170));
  474.  
  475. $hor=chunk_split(~$hor,$max_modules_1side,chr(170));
  476. $ver=chunk_split(~$ver,$max_modules_1side,chr(170));
  477. $hor=$hor.chr(170).$ver;
  478.  
  479. $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;
  480. $demerit_n4=floor(abs(( (100* (substr_count($ver,chr($bit_r))/($byte_num)) )-50)/5))*10;
  481.  
  482. $demerit_n2=0;
  483. preg_match_all('/'.chr($bit_r).chr($bit_r).'+/',$ver_and,$ptn_temp);
  484. foreach($ptn_temp[0] as $str_temp){
  485. $demerit_n2+=(strlen($str_temp)-1);
  486. }
  487. $ptn_temp=array();
  488. preg_match_all('/'.chr(255).chr(255).'+/',$ver_or,$ptn_temp);
  489. foreach($ptn_temp[0] as $str_temp){
  490. $demerit_n2+=(strlen($str_temp)-1);
  491. }
  492. $demerit_n2*=3;
  493.  
  494. $ptn_temp=array();
  495.  
  496. preg_match_all('/'.str_repeat(chr(255),5).'+|'.str_repeat(chr($bit_r),5).'+/',$hor,$ptn_temp);
  497. foreach($ptn_temp[0] as $str_temp){
  498. $demerit_n1+=(strlen($str_temp)-2);
  499. }
  500.  
  501. $demerit_score=$demerit_n1+$demerit_n2+$demerit_n3+$demerit_n4;
  502.  
  503. if ($demerit_score<=$min_demerit_score || !$i){
  504. $mask_number=$i;
  505. $min_demerit_score=$demerit_score;
  506. }
  507. }
  508.  
  509. $mask_content=1 << $mask_number;
  510.  
  511. $format_val=(($this->ecc << 3) | $mask_number);
  512.  
  513.  
  514. for($i=0;$i<15;$i++){
  515. $content=substr(self::$format_inf[$format_val],$i,1);
  516. $matrix_content[$format_x1[$i]][$format_y1[$i]]=$content * 255;
  517. $matrix_content[$format_x2[$i+1]][$format_y2[$i+1]]=$content * 255;
  518. }
  519.  
  520. $mib=$max_modules_1side+8;
  521. $image_size=$mib*$this->size;
  522. if ($image_size>1480)
  523. $this->showError('слишком большой размер изображения');
  524.  
  525. $im =imagecreate($image_size,$image_size);
  526.  
  527. $base_image = imagecreatefromstring(base64_decode($this->patterns['qrv'.$version]));
  528.  
  529. $color=imagecolorallocate($base_image,0,0,0);
  530.  
  531.  
  532. $mxe=4+$max_modules_1side;
  533.  
  534. for($ii=0,$i=4;$i<$mxe;$i++,$ii++){
  535. for($j=4,$jj=0;$j<$mxe;$j++,$jj++){
  536. if ($matrix_content[$ii][$jj] & $mask_content)
  537. imagesetpixel($base_image,$i,$j,$color);
  538. }
  539. }
  540.  
  541.  
  542. imagecopyresized($im,$base_image,0,0,0,0,$image_size,$image_size,$mib,$mib);
  543.  
  544. $function = 'image'.$this->type;
  545.  
  546. if(is_null($file))header('Content-type: image/'.$this->type);
  547. $function($im,$file);
  548.  
  549.  
  550. imagedestroy($base_image);
  551. imagedestroy($im);
  552.  
  553. }
  554.  
  555. /**
  556.   * строка - 8-ми битная кодировка
  557.   *
  558.   * @return int
  559.   */
  560. private function prepare8bit()
  561. {
  562. $this->codeword_num=array(0,0,0,0,0,0,0,0,0,0,
  563. 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
  564. 8,8,8,8,8,8,8,8,8,8,8,8,8,8);
  565.  
  566. $this->value[$this->counter]=4;
  567. $this->value[++$this->counter]=$this->datalength;
  568.  
  569. $this->bits[$this->counter]=8;
  570. $codeword_counter=$this->counter;
  571.  
  572. $this->counter++;
  573. for($i=0;$i<$this->datalength;$i++){
  574. $this->value[$this->counter]=ord(substr($this->data,$i,1));
  575. $this->bits[$this->counter]=8;
  576. $this->counter++;
  577. }
  578. return $codeword_counter;
  579. }
  580. /**
  581.   * строка - буквы и числа
  582.   *
  583.   * @return int
  584.   */
  585. private function prepareAlNum()
  586. {
  587. $this->codeword_num=array(0,0,0,0,0,0,0,0,0,0,
  588. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  589. 4,4,4,4,4,4,4,4,4,4,4,4,4,4);
  590.  
  591. $this->value[$this->counter]=2;
  592. $this->value[++$this->counter]=$this->datalength;
  593. $this->bits[$this->counter]=9;
  594. $codeword_counter=$this->counter;
  595.  
  596. $this->counter++;
  597. for($i=0;$i<$this->datalength;$i++){
  598. if (($i %2)==0){
  599. $this->value[$this->counter]= self::$alphanumeric_hash[substr($this->data,$i,1)];
  600. $this->bits[$this->counter]=6;
  601. } else {
  602. $this->value[$this->counter]= $this->value[$this->counter]*45+ self::$alphanumeric_hash[substr($this->data,$i,1)];
  603. $this->bits[$this->counter]=11;
  604. $this->counter++;
  605. }
  606. }
  607. return $codeword_counter;
  608. }
  609.  
  610. /**
  611.   * строка - числа
  612.   *
  613.   * @return int
  614.   */
  615. private function prepareNum()
  616. {
  617. $this->codeword_num=array(0,0,0,0,0,0,0,0,0,0,
  618. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  619. 4,4,4,4,4,4,4,4,4,4,4,4,4,4);
  620.  
  621. $this->value[$this->counter]=1;
  622. $this->value[++$this->counter]=$this->datalength;
  623. $this->bits[$this->counter]=10;
  624. $codeword_counter=$this->counter;
  625.  
  626. $this->counter++;
  627. for($i=0;$i<$this->datalength;$i++){
  628. if (($i % 3)==0){
  629. $this->value[$this->counter]=substr($this->data,$i,1);
  630. $this->bits[$this->counter]=4;
  631. } else {
  632. $this->value[$this->counter]=$this->value[$this->counter]*10+substr($this->data,$i,1);
  633. if (($i % 3)==1){
  634. $this->bits[$this->counter]=7;
  635. } else {
  636. $this->bits[$this->counter]=10;
  637. $this->counter++;
  638. }
  639. }
  640. }
  641. return $codeword_counter;
  642. }
  643.  
  644. /**
  645.   * Вывести сообщение с ошибкой
  646.   *
  647.   * @param string $str
  648.   * @return bool
  649.   */
  650. private function showError($str)
  651. {
  652. if(!empty($str))
  653. die('<b>Ошибка</b>: '.$str);
  654. return false;
  655. }
  656. }
  657. ?>

Класс полностью рабочий, основные png шаблоны перенесены из внешних файлов в сам класс, несколько ускорена обработка.

пример использования:

  1. <?php
  2. define('ROOT',getcwd());
  3. require_once 'qr.php';
  4.  
  5. $qr = new QR();
  6. $qr->setPath(ROOT.'/dataqr');
  7. $qr->draw('привет');
  8. /* сохранить в файл
  9. $qr->draw('привет','img.png');
  10. */
  11. ?>

Скачать одним файлом (tgz — 912 Кб) или посмотреть пример работы

Комментарии (6):
Олег 16-07-2009 11:15
Скажите, а есть ли какой-нибудь класс для распознавания QR?
Александр 26-01-2010 18:21
Можно ли создать генератор для создания кода с распознованием текста и № телефона на который можно сразу позвонить?
Padaboo 08-03-2010 12:52
А что, если база данных на файлах имеет место быть, почему бы не сделать что то типа, базы данных на QR?
Luge 08-03-2010 12:58
Padaboo, ты не учитываешь накладные расходы на раскодировку изображения. К тому же, QR имеет конечный максимально возможный размер. Я предпочту, всё же, более реальные велосипеды ;)
Александр 13-04-2010 12:57
А есть ли что-нибудь подобное для Delphi?
Luge 13-04-2010 13:14
Александр, должно быть. Никогда не интересовался. В любом случае, думаю, гугл об этом знает лучше ;)

Это архив блога. Добавление комментариев запрещено.

© Павел Новицкий 2009 - 2011
(: time: 27.3s, sql: 62, memory: 274Mb :)