qrcode.php 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161
  1. <?php
  2. define('QR_MODE_NUL',-1);
  3. define('QR_MODE_NUM',0);
  4. define('QR_MODE_AN',1);
  5. define('QR_MODE_8',2);
  6. define('QR_MODE_KANJI',3);
  7. define('QR_MODE_STRUCTURE',4);
  8. define('QR_ECLEVEL_L',0);
  9. define('QR_ECLEVEL_M',1);
  10. define('QR_ECLEVEL_Q',2);
  11. define('QR_ECLEVEL_H',3);
  12. define('QR_FORMAT_TEXT',0);
  13. define('QR_FORMAT_PNG',1);
  14. class qrstr {
  15. public static function set(&$srctab,$x,$y,$repl,$replLen = false) {
  16. $srctab[$y] = substr_replace($srctab[$y],($replLen !== false)?substr($repl,0,$replLen):$repl,$x,($replLen !== false)?$replLen:strlen($repl));
  17. }
  18. }
  19. define('QR_CACHEABLE',false);
  20. define('QR_CACHE_DIR',false);
  21. define('QR_LOG_DIR',false);
  22. define('QR_FIND_BEST_MASK',true);
  23. define('QR_FIND_FROM_RANDOM',2);
  24. define('QR_DEFAULT_MASK',2);
  25. define('QR_PNG_MAXIMUM_SIZE',1024);
  26. class QRtools {
  27. public static function binarize($frame)
  28. {
  29. $len = count($frame);
  30. foreach ($frame as &$frameLine) {
  31. for($i=0;$i<$len;$i++) {
  32. $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
  33. }
  34. }
  35. return $frame;
  36. }
  37. public static function tcpdfBarcodeArray($code,$mode = 'QR,L',$tcPdfVersion = '4.5.037')
  38. {
  39. $barcode_array = array();
  40. if (!is_array($mode))
  41. $mode = explode(',',$mode);
  42. $eccLevel = 'L';
  43. if (count($mode) >1) {
  44. $eccLevel = $mode[1];
  45. }
  46. $qrTab = QRcode::text($code,false,$eccLevel);
  47. $size = count($qrTab);
  48. $barcode_array['num_rows'] = $size;
  49. $barcode_array['num_cols'] = $size;
  50. $barcode_array['bcode'] = array();
  51. foreach ($qrTab as $line) {
  52. $arrAdd = array();
  53. foreach(str_split($line) as $char)
  54. $arrAdd[] = ($char=='1')?1:0;
  55. $barcode_array['bcode'][] = $arrAdd;
  56. }
  57. return $barcode_array;
  58. }
  59. public static function clearCache()
  60. {
  61. self::$frames = array();
  62. }
  63. public static function buildCache()
  64. {
  65. QRtools::markTime('before_build_cache');
  66. $mask = new QRmask();
  67. for ($a=1;$a <= QRSPEC_VERSION_MAX;$a++) {
  68. $frame = QRspec::newFrame($a);
  69. if (QR_IMAGE) {
  70. $fileName = QR_CACHE_DIR.'frame_'.$a.'.png';
  71. QRimage::png(self::binarize($frame),$fileName,1,0);
  72. }
  73. $width = count($frame);
  74. $bitMask = array_fill(0,$width,array_fill(0,$width,0));
  75. for ($maskNo=0;$maskNo<8;$maskNo++)
  76. $mask->makeMaskNo($maskNo,$width,$frame,$bitMask,true);
  77. }
  78. QRtools::markTime('after_build_cache');
  79. }
  80. public static function log($outfile,$err)
  81. {
  82. if (QR_LOG_DIR !== false) {
  83. if ($err != '') {
  84. if ($outfile !== false) {
  85. file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt',date('Y-m-d H:i:s').': '.$err,FILE_APPEND);
  86. }else {
  87. file_put_contents(QR_LOG_DIR.'errors.txt',date('Y-m-d H:i:s').': '.$err,FILE_APPEND);
  88. }
  89. }
  90. }
  91. }
  92. public static function dumpMask($frame)
  93. {
  94. $width = count($frame);
  95. for($y=0;$y<$width;$y++) {
  96. for($x=0;$x<$width;$x++) {
  97. echo ord($frame[$y][$x]).',';
  98. }
  99. }
  100. }
  101. public static function markTime($markerId)
  102. {
  103. list($usec,$sec) = explode(" ",microtime());
  104. $time = ((float)$usec +(float)$sec);
  105. if (!isset($GLOBALS['qr_time_bench']))
  106. $GLOBALS['qr_time_bench'] = array();
  107. $GLOBALS['qr_time_bench'][$markerId] = $time;
  108. }
  109. public static function timeBenchmark()
  110. {
  111. self::markTime('finish');
  112. $lastTime = 0;
  113. $startTime = 0;
  114. $p = 0;
  115. echo '<table cellpadding="3" cellspacing="1">
  116. <thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
  117. <tbody>';
  118. foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {
  119. if ($p >0) {
  120. echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime,6).'s</td></tr>';
  121. }else {
  122. $startTime = $thisTime;
  123. }
  124. $p++;
  125. $lastTime = $thisTime;
  126. }
  127. echo '</tbody><tfoot>
  128. <tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime,6).'s</td></tr>
  129. </tfoot>
  130. </table>';
  131. }
  132. }
  133. QRtools::markTime('start');
  134. define('QRSPEC_VERSION_MAX',40);
  135. define('QRSPEC_WIDTH_MAX',177);
  136. define('QRCAP_WIDTH',0);
  137. define('QRCAP_WORDS',1);
  138. define('QRCAP_REMINDER',2);
  139. define('QRCAP_EC',3);
  140. class QRspec {
  141. public static $capacity = array(
  142. array( 0,0,0,array( 0,0,0,0)),
  143. array( 21,26,0,array( 7,10,13,17)),
  144. array( 25,44,7,array( 10,16,22,28)),
  145. array( 29,70,7,array( 15,26,36,44)),
  146. array( 33,100,7,array( 20,36,52,64)),
  147. array( 37,134,7,array( 26,48,72,88)),
  148. array( 41,172,7,array( 36,64,96,112)),
  149. array( 45,196,0,array( 40,72,108,130)),
  150. array( 49,242,0,array( 48,88,132,156)),
  151. array( 53,292,0,array( 60,110,160,192)),
  152. array( 57,346,0,array( 72,130,192,224)),
  153. array( 61,404,0,array( 80,150,224,264)),
  154. array( 65,466,0,array( 96,176,260,308)),
  155. array( 69,532,0,array( 104,198,288,352)),
  156. array( 73,581,3,array( 120,216,320,384)),
  157. array( 77,655,3,array( 132,240,360,432)),
  158. array( 81,733,3,array( 144,280,408,480)),
  159. array( 85,815,3,array( 168,308,448,532)),
  160. array( 89,901,3,array( 180,338,504,588)),
  161. array( 93,991,3,array( 196,364,546,650)),
  162. array( 97,1085,3,array( 224,416,600,700)),
  163. array(101,1156,4,array( 224,442,644,750)),
  164. array(105,1258,4,array( 252,476,690,816)),
  165. array(109,1364,4,array( 270,504,750,900)),
  166. array(113,1474,4,array( 300,560,810,960)),
  167. array(117,1588,4,array( 312,588,870,1050)),
  168. array(121,1706,4,array( 336,644,952,1110)),
  169. array(125,1828,4,array( 360,700,1020,1200)),
  170. array(129,1921,3,array( 390,728,1050,1260)),
  171. array(133,2051,3,array( 420,784,1140,1350)),
  172. array(137,2185,3,array( 450,812,1200,1440)),
  173. array(141,2323,3,array( 480,868,1290,1530)),
  174. array(145,2465,3,array( 510,924,1350,1620)),
  175. array(149,2611,3,array( 540,980,1440,1710)),
  176. array(153,2761,3,array( 570,1036,1530,1800)),
  177. array(157,2876,0,array( 570,1064,1590,1890)),
  178. array(161,3034,0,array( 600,1120,1680,1980)),
  179. array(165,3196,0,array( 630,1204,1770,2100)),
  180. array(169,3362,0,array( 660,1260,1860,2220)),
  181. array(173,3532,0,array( 720,1316,1950,2310)),
  182. array(177,3706,0,array( 750,1372,2040,2430))
  183. );
  184. public static function getDataLength($version,$level)
  185. {
  186. return self::$capacity[$version][QRCAP_WORDS] -self::$capacity[$version][QRCAP_EC][$level];
  187. }
  188. public static function getECCLength($version,$level)
  189. {
  190. return self::$capacity[$version][QRCAP_EC][$level];
  191. }
  192. public static function getWidth($version)
  193. {
  194. return self::$capacity[$version][QRCAP_WIDTH];
  195. }
  196. public static function getRemainder($version)
  197. {
  198. return self::$capacity[$version][QRCAP_REMINDER];
  199. }
  200. public static function getMinimumVersion($size,$level)
  201. {
  202. for($i=1;$i<= QRSPEC_VERSION_MAX;$i++) {
  203. $words = self::$capacity[$i][QRCAP_WORDS] -self::$capacity[$i][QRCAP_EC][$level];
  204. if($words >= $size)
  205. return $i;
  206. }
  207. return -1;
  208. }
  209. public static $lengthTableBits = array(
  210. array(10,12,14),
  211. array( 9,11,13),
  212. array( 8,16,16),
  213. array( 8,10,12)
  214. );
  215. public static function lengthIndicator($mode,$version)
  216. {
  217. if ($mode == QR_MODE_STRUCTURE)
  218. return 0;
  219. if ($version <= 9) {
  220. $l = 0;
  221. }else if ($version <= 26) {
  222. $l = 1;
  223. }else {
  224. $l = 2;
  225. }
  226. return self::$lengthTableBits[$mode][$l];
  227. }
  228. public static function maximumWords($mode,$version)
  229. {
  230. if($mode == QR_MODE_STRUCTURE)
  231. return 3;
  232. if($version <= 9) {
  233. $l = 0;
  234. }else if($version <= 26) {
  235. $l = 1;
  236. }else {
  237. $l = 2;
  238. }
  239. $bits = self::$lengthTableBits[$mode][$l];
  240. $words = (1 <<$bits) -1;
  241. if($mode == QR_MODE_KANJI) {
  242. $words *= 2;
  243. }
  244. return $words;
  245. }
  246. public static $eccTable = array(
  247. array(array( 0,0),array( 0,0),array( 0,0),array( 0,0)),
  248. array(array( 1,0),array( 1,0),array( 1,0),array( 1,0)),
  249. array(array( 1,0),array( 1,0),array( 1,0),array( 1,0)),
  250. array(array( 1,0),array( 1,0),array( 2,0),array( 2,0)),
  251. array(array( 1,0),array( 2,0),array( 2,0),array( 4,0)),
  252. array(array( 1,0),array( 2,0),array( 2,2),array( 2,2)),
  253. array(array( 2,0),array( 4,0),array( 4,0),array( 4,0)),
  254. array(array( 2,0),array( 4,0),array( 2,4),array( 4,1)),
  255. array(array( 2,0),array( 2,2),array( 4,2),array( 4,2)),
  256. array(array( 2,0),array( 3,2),array( 4,4),array( 4,4)),
  257. array(array( 2,2),array( 4,1),array( 6,2),array( 6,2)),
  258. array(array( 4,0),array( 1,4),array( 4,4),array( 3,8)),
  259. array(array( 2,2),array( 6,2),array( 4,6),array( 7,4)),
  260. array(array( 4,0),array( 8,1),array( 8,4),array(12,4)),
  261. array(array( 3,1),array( 4,5),array(11,5),array(11,5)),
  262. array(array( 5,1),array( 5,5),array( 5,7),array(11,7)),
  263. array(array( 5,1),array( 7,3),array(15,2),array( 3,13)),
  264. array(array( 1,5),array(10,1),array( 1,15),array( 2,17)),
  265. array(array( 5,1),array( 9,4),array(17,1),array( 2,19)),
  266. array(array( 3,4),array( 3,11),array(17,4),array( 9,16)),
  267. array(array( 3,5),array( 3,13),array(15,5),array(15,10)),
  268. array(array( 4,4),array(17,0),array(17,6),array(19,6)),
  269. array(array( 2,7),array(17,0),array( 7,16),array(34,0)),
  270. array(array( 4,5),array( 4,14),array(11,14),array(16,14)),
  271. array(array( 6,4),array( 6,14),array(11,16),array(30,2)),
  272. array(array( 8,4),array( 8,13),array( 7,22),array(22,13)),
  273. array(array(10,2),array(19,4),array(28,6),array(33,4)),
  274. array(array( 8,4),array(22,3),array( 8,26),array(12,28)),
  275. array(array( 3,10),array( 3,23),array( 4,31),array(11,31)),
  276. array(array( 7,7),array(21,7),array( 1,37),array(19,26)),
  277. array(array( 5,10),array(19,10),array(15,25),array(23,25)),
  278. array(array(13,3),array( 2,29),array(42,1),array(23,28)),
  279. array(array(17,0),array(10,23),array(10,35),array(19,35)),
  280. array(array(17,1),array(14,21),array(29,19),array(11,46)),
  281. array(array(13,6),array(14,23),array(44,7),array(59,1)),
  282. array(array(12,7),array(12,26),array(39,14),array(22,41)),
  283. array(array( 6,14),array( 6,34),array(46,10),array( 2,64)),
  284. array(array(17,4),array(29,14),array(49,10),array(24,46)),
  285. array(array( 4,18),array(13,32),array(48,14),array(42,32)),
  286. array(array(20,4),array(40,7),array(43,22),array(10,67)),
  287. array(array(19,6),array(18,31),array(34,34),array(20,61)),
  288. );
  289. public static function getEccSpec($version,$level,array &$spec)
  290. {
  291. if (count($spec) <5) {
  292. $spec = array(0,0,0,0,0);
  293. }
  294. $b1 = self::$eccTable[$version][$level][0];
  295. $b2 = self::$eccTable[$version][$level][1];
  296. $data = self::getDataLength($version,$level);
  297. $ecc = self::getECCLength($version,$level);
  298. if($b2 == 0) {
  299. $spec[0] = $b1;
  300. $spec[1] = (int)($data / $b1);
  301. $spec[2] = (int)($ecc / $b1);
  302. $spec[3] = 0;
  303. $spec[4] = 0;
  304. }else {
  305. $spec[0] = $b1;
  306. $spec[1] = (int)($data / ($b1 +$b2));
  307. $spec[2] = (int)($ecc / ($b1 +$b2));
  308. $spec[3] = $b2;
  309. $spec[4] = $spec[1] +1;
  310. }
  311. }
  312. public static $alignmentPattern = array(
  313. array( 0,0),
  314. array( 0,0),array(18,0),array(22,0),array(26,0),array(30,0),
  315. array(34,0),array(22,38),array(24,42),array(26,46),array(28,50),
  316. array(30,54),array(32,58),array(34,62),array(26,46),array(26,48),
  317. array(26,50),array(30,54),array(30,56),array(30,58),array(34,62),
  318. array(28,50),array(26,50),array(30,54),array(28,54),array(32,58),
  319. array(30,58),array(34,62),array(26,50),array(30,54),array(26,52),
  320. array(30,56),array(34,60),array(30,58),array(34,62),array(30,54),
  321. array(24,50),array(28,54),array(32,58),array(26,54),array(30,58),
  322. );
  323. public static function putAlignmentMarker(array &$frame,$ox,$oy)
  324. {
  325. $finder = array(
  326. "\xa1\xa1\xa1\xa1\xa1",
  327. "\xa1\xa0\xa0\xa0\xa1",
  328. "\xa1\xa0\xa1\xa0\xa1",
  329. "\xa1\xa0\xa0\xa0\xa1",
  330. "\xa1\xa1\xa1\xa1\xa1"
  331. );
  332. $yStart = $oy-2;
  333. $xStart = $ox-2;
  334. for($y=0;$y<5;$y++) {
  335. QRstr::set($frame,$xStart,$yStart+$y,$finder[$y]);
  336. }
  337. }
  338. public static function putAlignmentPattern($version,&$frame,$width)
  339. {
  340. if($version <2)
  341. return;
  342. $d = self::$alignmentPattern[$version][1] -self::$alignmentPattern[$version][0];
  343. if($d <0) {
  344. $w = 2;
  345. }else {
  346. $w = (int)(($width -self::$alignmentPattern[$version][0]) / $d +2);
  347. }
  348. if($w * $w -3 == 1) {
  349. $x = self::$alignmentPattern[$version][0];
  350. $y = self::$alignmentPattern[$version][0];
  351. self::putAlignmentMarker($frame,$x,$y);
  352. return;
  353. }
  354. $cx = self::$alignmentPattern[$version][0];
  355. for($x=1;$x<$w -1;$x++) {
  356. self::putAlignmentMarker($frame,6,$cx);
  357. self::putAlignmentMarker($frame,$cx,6);
  358. $cx += $d;
  359. }
  360. $cy = self::$alignmentPattern[$version][0];
  361. for($y=0;$y<$w-1;$y++) {
  362. $cx = self::$alignmentPattern[$version][0];
  363. for($x=0;$x<$w-1;$x++) {
  364. self::putAlignmentMarker($frame,$cx,$cy);
  365. $cx += $d;
  366. }
  367. $cy += $d;
  368. }
  369. }
  370. public static $versionPattern = array(
  371. 0x07c94,0x085bc,0x09a99,0x0a4d3,0x0bbf6,0x0c762,0x0d847,0x0e60d,
  372. 0x0f928,0x10b78,0x1145d,0x12a17,0x13532,0x149a6,0x15683,0x168c9,
  373. 0x177ec,0x18ec4,0x191e1,0x1afab,0x1b08e,0x1cc1a,0x1d33f,0x1ed75,
  374. 0x1f250,0x209d5,0x216f0,0x228ba,0x2379f,0x24b0b,0x2542e,0x26a64,
  375. 0x27541,0x28c69
  376. );
  377. public static function getVersionPattern($version)
  378. {
  379. if($version <7 ||$version >QRSPEC_VERSION_MAX)
  380. return 0;
  381. return self::$versionPattern[$version -7];
  382. }
  383. public static $formatInfo = array(
  384. array(0x77c4,0x72f3,0x7daa,0x789d,0x662f,0x6318,0x6c41,0x6976),
  385. array(0x5412,0x5125,0x5e7c,0x5b4b,0x45f9,0x40ce,0x4f97,0x4aa0),
  386. array(0x355f,0x3068,0x3f31,0x3a06,0x24b4,0x2183,0x2eda,0x2bed),
  387. array(0x1689,0x13be,0x1ce7,0x19d0,0x0762,0x0255,0x0d0c,0x083b)
  388. );
  389. public static function getFormatInfo($mask,$level)
  390. {
  391. if($mask <0 ||$mask >7)
  392. return 0;
  393. if($level <0 ||$level >3)
  394. return 0;
  395. return self::$formatInfo[$level][$mask];
  396. }
  397. public static $frames = array();
  398. public static function putFinderPattern(&$frame,$ox,$oy)
  399. {
  400. $finder = array(
  401. "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
  402. "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
  403. "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
  404. "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
  405. "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
  406. "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
  407. "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
  408. );
  409. for($y=0;$y<7;$y++) {
  410. QRstr::set($frame,$ox,$oy+$y,$finder[$y]);
  411. }
  412. }
  413. public static function createFrame($version)
  414. {
  415. $width = self::$capacity[$version][QRCAP_WIDTH];
  416. $frameLine = str_repeat ("\0",$width);
  417. $frame = array_fill(0,$width,$frameLine);
  418. self::putFinderPattern($frame,0,0);
  419. self::putFinderPattern($frame,$width -7,0);
  420. self::putFinderPattern($frame,0,$width -7);
  421. $yOffset = $width -7;
  422. for($y=0;$y<7;$y++) {
  423. $frame[$y][7] = "\xc0";
  424. $frame[$y][$width -8] = "\xc0";
  425. $frame[$yOffset][7] = "\xc0";
  426. $yOffset++;
  427. }
  428. $setPattern = str_repeat("\xc0",8);
  429. QRstr::set($frame,0,7,$setPattern);
  430. QRstr::set($frame,$width-8,7,$setPattern);
  431. QRstr::set($frame,0,$width -8,$setPattern);
  432. $setPattern = str_repeat("\x84",9);
  433. QRstr::set($frame,0,8,$setPattern);
  434. QRstr::set($frame,$width -8,8,$setPattern,8);
  435. $yOffset = $width -8;
  436. for($y=0;$y<8;$y++,$yOffset++) {
  437. $frame[$y][8] = "\x84";
  438. $frame[$yOffset][8] = "\x84";
  439. }
  440. for($i=1;$i<$width-15;$i++) {
  441. $frame[6][7+$i] = chr(0x90 |($i &1));
  442. $frame[7+$i][6] = chr(0x90 |($i &1));
  443. }
  444. self::putAlignmentPattern($version,$frame,$width);
  445. if($version >= 7) {
  446. $vinf = self::getVersionPattern($version);
  447. $v = $vinf;
  448. for($x=0;$x<6;$x++) {
  449. for($y=0;$y<3;$y++) {
  450. $frame[($width -11)+$y][$x] = chr(0x88 |($v &1));
  451. $v = $v >>1;
  452. }
  453. }
  454. $v = $vinf;
  455. for($y=0;$y<6;$y++) {
  456. for($x=0;$x<3;$x++) {
  457. $frame[$y][$x+($width -11)] = chr(0x88 |($v &1));
  458. $v = $v >>1;
  459. }
  460. }
  461. }
  462. $frame[$width -8][8] = "\x81";
  463. return $frame;
  464. }
  465. public static function debug($frame,$binary_mode = false)
  466. {
  467. if ($binary_mode) {
  468. foreach ($frame as &$frameLine) {
  469. $frameLine = join('<span class="m">&nbsp;&nbsp;</span>',explode('0',$frameLine));
  470. $frameLine = join('&#9608;&#9608;',explode('1',$frameLine));
  471. }
  472. ;echo ' <style>
  473. .m { background-color: white; }
  474. </style>
  475. ';
  476. echo '<pre><tt><br/ ><br/ ><br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
  477. echo join("<br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;",$frame);
  478. echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';
  479. }else {
  480. foreach ($frame as &$frameLine) {
  481. $frameLine = join('<span class="m">&nbsp;</span>',explode("\xc0",$frameLine));
  482. $frameLine = join('<span class="m">&#9618;</span>',explode("\xc1",$frameLine));
  483. $frameLine = join('<span class="p">&nbsp;</span>',explode("\xa0",$frameLine));
  484. $frameLine = join('<span class="p">&#9618;</span>',explode("\xa1",$frameLine));
  485. $frameLine = join('<span class="s">&#9671;</span>',explode("\x84",$frameLine));
  486. $frameLine = join('<span class="s">&#9670;</span>',explode("\x85",$frameLine));
  487. $frameLine = join('<span class="x">&#9762;</span>',explode("\x81",$frameLine));
  488. $frameLine = join('<span class="c">&nbsp;</span>',explode("\x90",$frameLine));
  489. $frameLine = join('<span class="c">&#9719;</span>',explode("\x91",$frameLine));
  490. $frameLine = join('<span class="f">&nbsp;</span>',explode("\x88",$frameLine));
  491. $frameLine = join('<span class="f">&#9618;</span>',explode("\x89",$frameLine));
  492. $frameLine = join('&#9830;',explode("\x01",$frameLine));
  493. $frameLine = join('&#8901;',explode("\0",$frameLine));
  494. }
  495. ;echo ' <style>
  496. .p { background-color: yellow; }
  497. .m { background-color: #00FF00; }
  498. .s { background-color: #FF0000; }
  499. .c { background-color: aqua; }
  500. .x { background-color: pink; }
  501. .f { background-color: gold; }
  502. </style>
  503. ';
  504. echo "<pre><tt>";
  505. echo join("<br/ >",$frame);
  506. echo "</tt></pre>";
  507. }
  508. }
  509. public static function serial($frame)
  510. {
  511. return gzcompress(join("\n",$frame),9);
  512. }
  513. public static function unserial($code)
  514. {
  515. return explode("\n",gzuncompress($code));
  516. }
  517. public static function newFrame($version)
  518. {
  519. if($version <1 ||$version >QRSPEC_VERSION_MAX)
  520. return null;
  521. if(!isset(self::$frames[$version])) {
  522. $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat';
  523. if (QR_CACHEABLE) {
  524. if (file_exists($fileName)) {
  525. self::$frames[$version] = self::unserial(file_get_contents($fileName));
  526. }else {
  527. self::$frames[$version] = self::createFrame($version);
  528. file_put_contents($fileName,self::serial(self::$frames[$version]));
  529. }
  530. }else {
  531. self::$frames[$version] = self::createFrame($version);
  532. }
  533. }
  534. if(is_null(self::$frames[$version]))
  535. return null;
  536. return self::$frames[$version];
  537. }
  538. public static function rsBlockNum($spec) {return $spec[0] +$spec[3];}
  539. public static function rsBlockNum1($spec) {return $spec[0];}
  540. public static function rsDataCodes1($spec) {return $spec[1];}
  541. public static function rsEccCodes1($spec) {return $spec[2];}
  542. public static function rsBlockNum2($spec) {return $spec[3];}
  543. public static function rsDataCodes2($spec) {return $spec[4];}
  544. public static function rsEccCodes2($spec) {return $spec[2];}
  545. public static function rsDataLength($spec) {return ($spec[0] * $spec[1]) +($spec[3] * $spec[4]);}
  546. public static function rsEccLength($spec) {return ($spec[0] +$spec[3]) * $spec[2];}
  547. }
  548. define('QR_IMAGE',true);
  549. class QRimage {
  550. public static function png($frame,$filename = false,$pixelPerPoint = 4,$outerFrame = 4,$saveandprint=FALSE)
  551. {
  552. $image = self::image($frame,$pixelPerPoint,$outerFrame);
  553. if ($filename === false) {
  554. Header("Content-type: image/png");
  555. ImagePng($image);
  556. }else {
  557. if($saveandprint===TRUE){
  558. ImagePng($image,$filename);
  559. header("Content-type: image/png");
  560. ImagePng($image);
  561. }else{
  562. ImagePng($image,$filename);
  563. }
  564. }
  565. ImageDestroy($image);
  566. }
  567. public static function jpg($frame,$filename = false,$pixelPerPoint = 8,$outerFrame = 4,$q = 85)
  568. {
  569. $image = self::image($frame,$pixelPerPoint,$outerFrame);
  570. if ($filename === false) {
  571. Header("Content-type: image/jpeg");
  572. ImageJpeg($image,null,$q);
  573. }else {
  574. ImageJpeg($image,$filename,$q);
  575. }
  576. ImageDestroy($image);
  577. }
  578. private static function image($frame,$pixelPerPoint = 4,$outerFrame = 4)
  579. {
  580. $h = count($frame);
  581. $w = strlen($frame[0]);
  582. $imgW = $w +2*$outerFrame;
  583. $imgH = $h +2*$outerFrame;
  584. $base_image =ImageCreate($imgW,$imgH);
  585. $col[0] = ImageColorAllocate($base_image,255,255,255);
  586. $col[1] = ImageColorAllocate($base_image,0,0,0);
  587. imagefill($base_image,0,0,$col[0]);
  588. for($y=0;$y<$h;$y++) {
  589. for($x=0;$x<$w;$x++) {
  590. if ($frame[$y][$x] == '1') {
  591. ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]);
  592. }
  593. }
  594. }
  595. $target_image =ImageCreate($imgW * $pixelPerPoint,$imgH * $pixelPerPoint);
  596. ImageCopyResized($target_image,$base_image,0,0,0,0,$imgW * $pixelPerPoint,$imgH * $pixelPerPoint,$imgW,$imgH);
  597. ImageDestroy($base_image);
  598. return $target_image;
  599. }
  600. }
  601. define('STRUCTURE_HEADER_BITS',20);
  602. define('MAX_STRUCTURED_SYMBOLS',16);
  603. class QRinputItem {
  604. public $mode;
  605. public $size;
  606. public $data;
  607. public $bstream;
  608. public function __construct($mode,$size,$data,$bstream = null)
  609. {
  610. $setData = array_slice($data,0,$size);
  611. if (count($setData) <$size) {
  612. $setData = array_merge($setData,array_fill(0,$size-count($setData),0));
  613. }
  614. if(!QRinput::check($mode,$size,$setData)) {
  615. throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
  616. return null;
  617. }
  618. $this->mode = $mode;
  619. $this->size = $size;
  620. $this->data = $setData;
  621. $this->bstream = $bstream;
  622. }
  623. public function encodeModeNum($version)
  624. {
  625. try {
  626. $words = (int)($this->size / 3);
  627. $bs = new QRbitstream();
  628. $val = 0x1;
  629. $bs->appendNum(4,$val);
  630. $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM,$version),$this->size);
  631. for($i=0;$i<$words;$i++) {
  632. $val = (ord($this->data[$i*3 ]) -ord('0')) * 100;
  633. $val += (ord($this->data[$i*3+1]) -ord('0')) * 10;
  634. $val += (ord($this->data[$i*3+2]) -ord('0'));
  635. $bs->appendNum(10,$val);
  636. }
  637. if($this->size -$words * 3 == 1) {
  638. $val = ord($this->data[$words*3]) -ord('0');
  639. $bs->appendNum(4,$val);
  640. }else if($this->size -$words * 3 == 2) {
  641. $val = (ord($this->data[$words*3 ]) -ord('0')) * 10;
  642. $val += (ord($this->data[$words*3+1]) -ord('0'));
  643. $bs->appendNum(7,$val);
  644. }
  645. $this->bstream = $bs;
  646. return 0;
  647. }catch (Exception $e) {
  648. return -1;
  649. }
  650. }
  651. public function encodeModeAn($version)
  652. {
  653. try {
  654. $words = (int)($this->size / 2);
  655. $bs = new QRbitstream();
  656. $bs->appendNum(4,0x02);
  657. $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN,$version),$this->size);
  658. for($i=0;$i<$words;$i++) {
  659. $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45;
  660. $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));
  661. $bs->appendNum(11,$val);
  662. }
  663. if($this->size &1) {
  664. $val = QRinput::lookAnTable(ord($this->data[$words * 2]));
  665. $bs->appendNum(6,$val);
  666. }
  667. $this->bstream = $bs;
  668. return 0;
  669. }catch (Exception $e) {
  670. return -1;
  671. }
  672. }
  673. public function encodeMode8($version)
  674. {
  675. try {
  676. $bs = new QRbitstream();
  677. $bs->appendNum(4,0x4);
  678. $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8,$version),$this->size);
  679. for($i=0;$i<$this->size;$i++) {
  680. $bs->appendNum(8,ord($this->data[$i]));
  681. }
  682. $this->bstream = $bs;
  683. return 0;
  684. }catch (Exception $e) {
  685. return -1;
  686. }
  687. }
  688. public function encodeModeKanji($version)
  689. {
  690. try {
  691. $bs = new QRbitrtream();
  692. $bs->appendNum(4,0x8);
  693. $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI,$version),(int)($this->size / 2));
  694. for($i=0;$i<$this->size;$i+=2) {
  695. $val = (ord($this->data[$i]) <<8) |ord($this->data[$i+1]);
  696. if($val <= 0x9ffc) {
  697. $val -= 0x8140;
  698. }else {
  699. $val -= 0xc140;
  700. }
  701. $h = ($val >>8) * 0xc0;
  702. $val = ($val &0xff) +$h;
  703. $bs->appendNum(13,$val);
  704. }
  705. $this->bstream = $bs;
  706. return 0;
  707. }catch (Exception $e) {
  708. return -1;
  709. }
  710. }
  711. public function encodeModeStructure()
  712. {
  713. try {
  714. $bs = new QRbitstream();
  715. $bs->appendNum(4,0x03);
  716. $bs->appendNum(4,ord($this->data[1]) -1);
  717. $bs->appendNum(4,ord($this->data[0]) -1);
  718. $bs->appendNum(8,ord($this->data[2]));
  719. $this->bstream = $bs;
  720. return 0;
  721. }catch (Exception $e) {
  722. return -1;
  723. }
  724. }
  725. public function estimateBitStreamSizeOfEntry($version)
  726. {
  727. $bits = 0;
  728. if($version == 0)
  729. $version = 1;
  730. switch($this->mode) {
  731. case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size);break;
  732. case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size);break;
  733. case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size);break;
  734. case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break;
  735. case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS;
  736. default:
  737. return 0;
  738. }
  739. $l = QRspec::lengthIndicator($this->mode,$version);
  740. $m = 1 <<$l;
  741. $num = (int)(($this->size +$m -1) / $m);
  742. $bits += $num * (4 +$l);
  743. return $bits;
  744. }
  745. public function encodeBitStream($version)
  746. {
  747. try {
  748. unset($this->bstream);
  749. $words = QRspec::maximumWords($this->mode,$version);
  750. if($this->size >$words) {
  751. $st1 = new QRinputItem($this->mode,$words,$this->data);
  752. $st2 = new QRinputItem($this->mode,$this->size -$words,array_slice($this->data,$words));
  753. $st1->encodeBitStream($version);
  754. $st2->encodeBitStream($version);
  755. $this->bstream = new QRbitstream();
  756. $this->bstream->append($st1->bstream);
  757. $this->bstream->append($st2->bstream);
  758. unset($st1);
  759. unset($st2);
  760. }else {
  761. $ret = 0;
  762. switch($this->mode) {
  763. case QR_MODE_NUM: $ret = $this->encodeModeNum($version);break;
  764. case QR_MODE_AN: $ret = $this->encodeModeAn($version);break;
  765. case QR_MODE_8: $ret = $this->encodeMode8($version);break;
  766. case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break;
  767. case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure();break;
  768. default:
  769. break;
  770. }
  771. if($ret <0)
  772. return -1;
  773. }
  774. return $this->bstream->size();
  775. }catch (Exception $e) {
  776. return -1;
  777. }
  778. }
  779. };
  780. class QRinput {
  781. public $items;
  782. private $version;
  783. private $level;
  784. public function __construct($version = 0,$level = QR_ECLEVEL_L)
  785. {
  786. if ($version <0 ||$version >QRSPEC_VERSION_MAX ||$level >QR_ECLEVEL_H) {
  787. throw new Exception('Invalid version no');
  788. return NULL;
  789. }
  790. $this->version = $version;
  791. $this->level = $level;
  792. }
  793. public function getVersion()
  794. {
  795. return $this->version;
  796. }
  797. public function setVersion($version)
  798. {
  799. if($version <0 ||$version >QRSPEC_VERSION_MAX) {
  800. throw new Exception('Invalid version no');
  801. return -1;
  802. }
  803. $this->version = $version;
  804. return 0;
  805. }
  806. public function getErrorCorrectionLevel()
  807. {
  808. return $this->level;
  809. }
  810. public function setErrorCorrectionLevel($level)
  811. {
  812. if($level >QR_ECLEVEL_H) {
  813. throw new Exception('Invalid ECLEVEL');
  814. return -1;
  815. }
  816. $this->level = $level;
  817. return 0;
  818. }
  819. public function appendEntry(QRinputItem $entry)
  820. {
  821. $this->items[] = $entry;
  822. }
  823. public function append($mode,$size,$data)
  824. {
  825. try {
  826. $entry = new QRinputItem($mode,$size,$data);
  827. $this->items[] = $entry;
  828. return 0;
  829. }catch (Exception $e) {
  830. return -1;
  831. }
  832. }
  833. public function insertStructuredAppendHeader($size,$index,$parity)
  834. {
  835. if( $size >MAX_STRUCTURED_SYMBOLS ) {
  836. throw new Exception('insertStructuredAppendHeader wrong size');
  837. }
  838. if( $index <= 0 ||$index >MAX_STRUCTURED_SYMBOLS ) {
  839. throw new Exception('insertStructuredAppendHeader wrong index');
  840. }
  841. $buf = array($size,$index,$parity);
  842. try {
  843. $entry = new QRinputItem(QR_MODE_STRUCTURE,3,buf);
  844. array_unshift($this->items,$entry);
  845. return 0;
  846. }catch (Exception $e) {
  847. return -1;
  848. }
  849. }
  850. public function calcParity()
  851. {
  852. $parity = 0;
  853. foreach($this->items as $item) {
  854. if($item->mode != QR_MODE_STRUCTURE) {
  855. for($i=$item->size-1;$i>=0;$i--) {
  856. $parity ^= $item->data[$i];
  857. }
  858. }
  859. }
  860. return $parity;
  861. }
  862. public static function checkModeNum($size,$data)
  863. {
  864. for($i=0;$i<$size;$i++) {
  865. if((ord($data[$i]) <ord('0')) ||(ord($data[$i]) >ord('9'))){
  866. return false;
  867. }
  868. }
  869. return true;
  870. }
  871. public static function estimateBitsModeNum($size)
  872. {
  873. $w = (int)$size / 3;
  874. $bits = $w * 10;
  875. switch($size -$w * 3) {
  876. case 1:
  877. $bits += 4;
  878. break;
  879. case 2:
  880. $bits += 7;
  881. break;
  882. default:
  883. break;
  884. }
  885. return $bits;
  886. }
  887. public static $anTable = array(
  888. -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  889. -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  890. 36,-1,-1,-1,37,38,-1,-1,-1,-1,39,40,-1,41,42,43,
  891. 0,1,2,3,4,5,6,7,8,9,44,-1,-1,-1,-1,-1,
  892. -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
  893. 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
  894. -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  895. -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  896. );
  897. public static function lookAnTable($c)
  898. {
  899. return (($c >127)?-1:self::$anTable[$c]);
  900. }
  901. public static function checkModeAn($size,$data)
  902. {
  903. for($i=0;$i<$size;$i++) {
  904. if (self::lookAnTable(ord($data[$i])) == -1) {
  905. return false;
  906. }
  907. }
  908. return true;
  909. }
  910. public static function estimateBitsModeAn($size)
  911. {
  912. $w = (int)($size / 2);
  913. $bits = $w * 11;
  914. if($size &1) {
  915. $bits += 6;
  916. }
  917. return $bits;
  918. }
  919. public static function estimateBitsMode8($size)
  920. {
  921. return $size * 8;
  922. }
  923. public function estimateBitsModeKanji($size)
  924. {
  925. return (int)(($size / 2) * 13);
  926. }
  927. public static function checkModeKanji($size,$data)
  928. {
  929. if($size &1)
  930. return false;
  931. for($i=0;$i<$size;$i+=2) {
  932. $val = (ord($data[$i]) <<8) |ord($data[$i+1]);
  933. if( $val <0x8140
  934. ||($val >0x9ffc &&$val <0xe040)
  935. ||$val >0xebbf) {
  936. return false;
  937. }
  938. }
  939. return true;
  940. }
  941. public static function check($mode,$size,$data)
  942. {
  943. if($size <= 0)
  944. return false;
  945. switch($mode) {
  946. case QR_MODE_NUM: return self::checkModeNum($size,$data);break;
  947. case QR_MODE_AN: return self::checkModeAn($size,$data);break;
  948. case QR_MODE_KANJI: return self::checkModeKanji($size,$data);break;
  949. case QR_MODE_8: return true;break;
  950. case QR_MODE_STRUCTURE: return true;break;
  951. default:
  952. break;
  953. }
  954. return false;
  955. }
  956. public function estimateBitStreamSize($version)
  957. {
  958. $bits = 0;
  959. foreach($this->items as $item) {
  960. $bits += $item->estimateBitStreamSizeOfEntry($version);
  961. }
  962. return $bits;
  963. }
  964. public function estimateVersion()
  965. {
  966. $version = 0;
  967. $prev = 0;
  968. do {
  969. $prev = $version;
  970. $bits = $this->estimateBitStreamSize($prev);
  971. $version = QRspec::getMinimumVersion((int)(($bits +7) / 8),$this->level);
  972. if ($version <0) {
  973. return -1;
  974. }
  975. }while ($version >$prev);
  976. return $version;
  977. }
  978. public static function lengthOfCode($mode,$version,$bits)
  979. {
  980. $payload = $bits -4 -QRspec::lengthIndicator($mode,$version);
  981. switch($mode) {
  982. case QR_MODE_NUM:
  983. $chunks = (int)($payload / 10);
  984. $remain = $payload -$chunks * 10;
  985. $size = $chunks * 3;
  986. if($remain >= 7) {
  987. $size += 2;
  988. }else if($remain >= 4) {
  989. $size += 1;
  990. }
  991. break;
  992. case QR_MODE_AN:
  993. $chunks = (int)($payload / 11);
  994. $remain = $payload -$chunks * 11;
  995. $size = $chunks * 2;
  996. if($remain >= 6)
  997. $size++;
  998. break;
  999. case QR_MODE_8:
  1000. $size = (int)($payload / 8);
  1001. break;
  1002. case QR_MODE_KANJI:
  1003. $size = (int)(($payload / 13) * 2);
  1004. break;
  1005. case QR_MODE_STRUCTURE:
  1006. $size = (int)($payload / 8);
  1007. break;
  1008. default:
  1009. $size = 0;
  1010. break;
  1011. }
  1012. $maxsize = QRspec::maximumWords($mode,$version);
  1013. if($size <0) $size = 0;
  1014. if($size >$maxsize) $size = $maxsize;
  1015. return $size;
  1016. }
  1017. public function createBitStream()
  1018. {
  1019. $total = 0;
  1020. foreach($this->items as $item) {
  1021. $bits = $item->encodeBitStream($this->version);
  1022. if($bits <0)
  1023. return -1;
  1024. $total += $bits;
  1025. }
  1026. return $total;
  1027. }
  1028. public function convertData()
  1029. {
  1030. $ver = $this->estimateVersion();
  1031. if($ver >$this->getVersion()) {
  1032. $this->setVersion($ver);
  1033. }
  1034. for(;;) {
  1035. $bits = $this->createBitStream();
  1036. if($bits <0)
  1037. return -1;
  1038. $ver = QRspec::getMinimumVersion((int)(($bits +7) / 8),$this->level);
  1039. if($ver <0) {
  1040. throw new Exception('WRONG VERSION');
  1041. return -1;
  1042. }else if($ver >$this->getVersion()) {
  1043. $this->setVersion($ver);
  1044. }else {
  1045. break;
  1046. }
  1047. }
  1048. return 0;
  1049. }
  1050. public function appendPaddingBit(&$bstream)
  1051. {
  1052. $bits = $bstream->size();
  1053. $maxwords = QRspec::getDataLength($this->version,$this->level);
  1054. $maxbits = $maxwords * 8;
  1055. if ($maxbits == $bits) {
  1056. return 0;
  1057. }
  1058. if ($maxbits -$bits <5) {
  1059. return $bstream->appendNum($maxbits -$bits,0);
  1060. }
  1061. $bits += 4;
  1062. $words = (int)(($bits +7) / 8);
  1063. $padding = new QRbitstream();
  1064. $ret = $padding->appendNum($words * 8 -$bits +4,0);
  1065. if($ret <0)
  1066. return $ret;
  1067. $padlen = $maxwords -$words;
  1068. if($padlen >0) {
  1069. $padbuf = array();
  1070. for($i=0;$i<$padlen;$i++) {
  1071. $padbuf[$i] = ($i&1)?0x11:0xec;
  1072. }
  1073. $ret = $padding->appendBytes($padlen,$padbuf);
  1074. if($ret <0)
  1075. return $ret;
  1076. }
  1077. $ret = $bstream->append($padding);
  1078. return $ret;
  1079. }
  1080. public function mergeBitStream()
  1081. {
  1082. if($this->convertData() <0) {
  1083. return null;
  1084. }
  1085. $bstream = new QRbitstream();
  1086. foreach($this->items as $item) {
  1087. $ret = $bstream->append($item->bstream);
  1088. if($ret <0) {
  1089. return null;
  1090. }
  1091. }
  1092. return $bstream;
  1093. }
  1094. public function getBitStream()
  1095. {
  1096. $bstream = $this->mergeBitStream();
  1097. if($bstream == null) {
  1098. return null;
  1099. }
  1100. $ret = $this->appendPaddingBit($bstream);
  1101. if($ret <0) {
  1102. return null;
  1103. }
  1104. return $bstream;
  1105. }
  1106. public function getByteStream()
  1107. {
  1108. $bstream = $this->getBitStream();
  1109. if($bstream == null) {
  1110. return null;
  1111. }
  1112. return $bstream->toByte();
  1113. }
  1114. }
  1115. class QRbitstream {
  1116. public $data = array();
  1117. public function size()
  1118. {
  1119. return count($this->data);
  1120. }
  1121. public function allocate($setLength)
  1122. {
  1123. $this->data = array_fill(0,$setLength,0);
  1124. return 0;
  1125. }
  1126. public static function newFromNum($bits,$num)
  1127. {
  1128. $bstream = new QRbitstream();
  1129. $bstream->allocate($bits);
  1130. $mask = 1 <<($bits -1);
  1131. for($i=0;$i<$bits;$i++) {
  1132. if($num &$mask) {
  1133. $bstream->data[$i] = 1;
  1134. }else {
  1135. $bstream->data[$i] = 0;
  1136. }
  1137. $mask = $mask >>1;
  1138. }
  1139. return $bstream;
  1140. }
  1141. public static function newFromBytes($size,$data)
  1142. {
  1143. $bstream = new QRbitstream();
  1144. $bstream->allocate($size * 8);
  1145. $p=0;
  1146. for($i=0;$i<$size;$i++) {
  1147. $mask = 0x80;
  1148. for($j=0;$j<8;$j++) {
  1149. if($data[$i] &$mask) {
  1150. $bstream->data[$p] = 1;
  1151. }else {
  1152. $bstream->data[$p] = 0;
  1153. }
  1154. $p++;
  1155. $mask = $mask >>1;
  1156. }
  1157. }
  1158. return $bstream;
  1159. }
  1160. public function append(QRbitstream $arg)
  1161. {
  1162. if (is_null($arg)) {
  1163. return -1;
  1164. }
  1165. if($arg->size() == 0) {
  1166. return 0;
  1167. }
  1168. if($this->size() == 0) {
  1169. $this->data = $arg->data;
  1170. return 0;
  1171. }
  1172. $this->data = array_values(array_merge($this->data,$arg->data));
  1173. return 0;
  1174. }
  1175. public function appendNum($bits,$num)
  1176. {
  1177. if ($bits == 0)
  1178. return 0;
  1179. $b = QRbitstream::newFromNum($bits,$num);
  1180. if(is_null($b))
  1181. return -1;
  1182. $ret = $this->append($b);
  1183. unset($b);
  1184. return $ret;
  1185. }
  1186. public function appendBytes($size,$data)
  1187. {
  1188. if ($size == 0)
  1189. return 0;
  1190. $b = QRbitstream::newFromBytes($size,$data);
  1191. if(is_null($b))
  1192. return -1;
  1193. $ret = $this->append($b);
  1194. unset($b);
  1195. return $ret;
  1196. }
  1197. public function toByte()
  1198. {
  1199. $size = $this->size();
  1200. if($size == 0) {
  1201. return array();
  1202. }
  1203. $data = array_fill(0,(int)(($size +7) / 8),0);
  1204. $bytes = (int)($size / 8);
  1205. $p = 0;
  1206. for($i=0;$i<$bytes;$i++) {
  1207. $v = 0;
  1208. for($j=0;$j<8;$j++) {
  1209. $v = $v <<1;
  1210. $v |= $this->data[$p];
  1211. $p++;
  1212. }
  1213. $data[$i] = $v;
  1214. }
  1215. if($size &7) {
  1216. $v = 0;
  1217. for($j=0;$j<($size &7);$j++) {
  1218. $v = $v <<1;
  1219. $v |= $this->data[$p];
  1220. $p++;
  1221. }
  1222. $data[$bytes] = $v;
  1223. }
  1224. return $data;
  1225. }
  1226. }
  1227. class QRsplit {
  1228. public $dataStr = '';
  1229. public $input;
  1230. public $modeHint;
  1231. public function __construct($dataStr,$input,$modeHint)
  1232. {
  1233. $this->dataStr = $dataStr;
  1234. $this->input = $input;
  1235. $this->modeHint = $modeHint;
  1236. }
  1237. public static function isdigitat($str,$pos)
  1238. {
  1239. if ($pos >= strlen($str))
  1240. return false;
  1241. return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
  1242. }
  1243. public static function isalnumat($str,$pos)
  1244. {
  1245. if ($pos >= strlen($str))
  1246. return false;
  1247. return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
  1248. }
  1249. public function identifyMode($pos)
  1250. {
  1251. if ($pos >= strlen($this->dataStr))
  1252. return QR_MODE_NUL;
  1253. $c = $this->dataStr[$pos];
  1254. if(self::isdigitat($this->dataStr,$pos)) {
  1255. return QR_MODE_NUM;
  1256. }else if(self::isalnumat($this->dataStr,$pos)) {
  1257. return QR_MODE_AN;
  1258. }else if($this->modeHint == QR_MODE_KANJI) {
  1259. if ($pos+1 <strlen($this->dataStr))
  1260. {
  1261. $d = $this->dataStr[$pos+1];
  1262. $word = (ord($c) <<8) |ord($d);
  1263. if(($word >= 0x8140 &&$word <= 0x9ffc) ||($word >= 0xe040 &&$word <= 0xebbf)) {
  1264. return QR_MODE_KANJI;
  1265. }
  1266. }
  1267. }
  1268. return QR_MODE_8;
  1269. }
  1270. public function eatNum()
  1271. {
  1272. $ln = QRspec::lengthIndicator(QR_MODE_NUM,$this->input->getVersion());
  1273. $p = 0;
  1274. while(self::isdigitat($this->dataStr,$p)) {
  1275. $p++;
  1276. }
  1277. $run = $p;
  1278. $mode = $this->identifyMode($p);
  1279. if($mode == QR_MODE_8) {
  1280. $dif = QRinput::estimateBitsModeNum($run) +4 +$ln
  1281. +QRinput::estimateBitsMode8(1)
  1282. -QRinput::estimateBitsMode8($run +1);
  1283. if($dif >0) {
  1284. return $this->eat8();
  1285. }
  1286. }
  1287. if($mode == QR_MODE_AN) {
  1288. $dif = QRinput::estimateBitsModeNum($run) +4 +$ln
  1289. +QRinput::estimateBitsModeAn(1)
  1290. -QRinput::estimateBitsModeAn($run +1);
  1291. if($dif >0) {
  1292. return $this->eatAn();
  1293. }
  1294. }
  1295. $ret = $this->input->append(QR_MODE_NUM,$run,str_split($this->dataStr));
  1296. if($ret <0)
  1297. return -1;
  1298. return $run;
  1299. }
  1300. public function eatAn()
  1301. {
  1302. $la = QRspec::lengthIndicator(QR_MODE_AN,$this->input->getVersion());
  1303. $ln = QRspec::lengthIndicator(QR_MODE_NUM,$this->input->getVersion());
  1304. $p = 0;
  1305. while(self::isalnumat($this->dataStr,$p)) {
  1306. if(self::isdigitat($this->dataStr,$p)) {
  1307. $q = $p;
  1308. while(self::isdigitat($this->dataStr,$q)) {
  1309. $q++;
  1310. }
  1311. $dif = QRinput::estimateBitsModeAn($p)
  1312. +QRinput::estimateBitsModeNum($q -$p) +4 +$ln
  1313. -QRinput::estimateBitsModeAn($q);
  1314. if($dif <0) {
  1315. break;
  1316. }else {
  1317. $p = $q;
  1318. }
  1319. }else {
  1320. $p++;
  1321. }
  1322. }
  1323. $run = $p;
  1324. if(!self::isalnumat($this->dataStr,$p)) {
  1325. $dif = QRinput::estimateBitsModeAn($run) +4 +$la
  1326. +QRinput::estimateBitsMode8(1)
  1327. -QRinput::estimateBitsMode8($run +1);
  1328. if($dif >0) {
  1329. return $this->eat8();
  1330. }
  1331. }
  1332. $ret = $this->input->append(QR_MODE_AN,$run,str_split($this->dataStr));
  1333. if($ret <0)
  1334. return -1;
  1335. return $run;
  1336. }
  1337. public function eatKanji()
  1338. {
  1339. $p = 0;
  1340. while($this->identifyMode($p) == QR_MODE_KANJI) {
  1341. $p += 2;
  1342. }
  1343. $ret = $this->input->append(QR_MODE_KANJI,$p,str_split($this->dataStr));
  1344. if($ret <0)
  1345. return -1;
  1346. return $run;
  1347. }
  1348. public function eat8()
  1349. {
  1350. $la = QRspec::lengthIndicator(QR_MODE_AN,$this->input->getVersion());
  1351. $ln = QRspec::lengthIndicator(QR_MODE_NUM,$this->input->getVersion());
  1352. $p = 1;
  1353. $dataStrLen = strlen($this->dataStr);
  1354. while($p <$dataStrLen) {
  1355. $mode = $this->identifyMode($p);
  1356. if($mode == QR_MODE_KANJI) {
  1357. break;
  1358. }
  1359. if($mode == QR_MODE_NUM) {
  1360. $q = $p;
  1361. while(self::isdigitat($this->dataStr,$q)) {
  1362. $q++;
  1363. }
  1364. $dif = QRinput::estimateBitsMode8($p)
  1365. +QRinput::estimateBitsModeNum($q -$p) +4 +$ln
  1366. -QRinput::estimateBitsMode8($q);
  1367. if($dif <0) {
  1368. break;
  1369. }else {
  1370. $p = $q;
  1371. }
  1372. }else if($mode == QR_MODE_AN) {
  1373. $q = $p;
  1374. while(self::isalnumat($this->dataStr,$q)) {
  1375. $q++;
  1376. }
  1377. $dif = QRinput::estimateBitsMode8($p)
  1378. +QRinput::estimateBitsModeAn($q -$p) +4 +$la
  1379. -QRinput::estimateBitsMode8($q);
  1380. if($dif <0) {
  1381. break;
  1382. }else {
  1383. $p = $q;
  1384. }
  1385. }else {
  1386. $p++;
  1387. }
  1388. }
  1389. $run = $p;
  1390. $ret = $this->input->append(QR_MODE_8,$run,str_split($this->dataStr));
  1391. if($ret <0)
  1392. return -1;
  1393. return $run;
  1394. }
  1395. public function splitString()
  1396. {
  1397. while (strlen($this->dataStr) >0)
  1398. {
  1399. if($this->dataStr == '')
  1400. return 0;
  1401. $mode = $this->identifyMode(0);
  1402. switch ($mode) {
  1403. case QR_MODE_NUM: $length = $this->eatNum();break;
  1404. case QR_MODE_AN: $length = $this->eatAn();break;
  1405. case QR_MODE_KANJI:
  1406. if ($hint == QR_MODE_KANJI)
  1407. $length = $this->eatKanji();
  1408. else $length = $this->eat8();
  1409. break;
  1410. default: $length = $this->eat8();break;
  1411. }
  1412. if($length == 0) return 0;
  1413. if($length <0) return -1;
  1414. $this->dataStr = substr($this->dataStr,$length);
  1415. }
  1416. }
  1417. public function toUpper()
  1418. {
  1419. $stringLen = strlen($this->dataStr);
  1420. $p = 0;
  1421. while ($p<$stringLen) {
  1422. $mode = self::identifyMode(substr($this->dataStr,$p),$this->modeHint);
  1423. if($mode == QR_MODE_KANJI) {
  1424. $p += 2;
  1425. }else {
  1426. if (ord($this->dataStr[$p]) >= ord('a') &&ord($this->dataStr[$p]) <= ord('z')) {
  1427. $this->dataStr[$p] = chr(ord($this->dataStr[$p]) -32);
  1428. }
  1429. $p++;
  1430. }
  1431. }
  1432. return $this->dataStr;
  1433. }
  1434. public static function splitStringToQRinput($string,QRinput $input,$modeHint,$casesensitive = true)
  1435. {
  1436. if(is_null($string) ||$string == '\0'||$string == '') {
  1437. throw new Exception('empty string!!!');
  1438. }
  1439. $split = new QRsplit($string,$input,$modeHint);
  1440. if(!$casesensitive)
  1441. $split->toUpper();
  1442. return $split->splitString();
  1443. }
  1444. }
  1445. class QRrsItem {
  1446. public $mm;
  1447. public $nn;
  1448. public $alpha_to = array();
  1449. public $index_of = array();
  1450. public $genpoly = array();
  1451. public $nroots;
  1452. public $fcr;
  1453. public $prim;
  1454. public $iprim;
  1455. public $pad;
  1456. public $gfpoly;
  1457. public function modnn($x)
  1458. {
  1459. while ($x >= $this->nn) {
  1460. $x -= $this->nn;
  1461. $x = ($x >>$this->mm) +($x &$this->nn);
  1462. }
  1463. return $x;
  1464. }
  1465. public static function init_rs_char($symsize,$gfpoly,$fcr,$prim,$nroots,$pad)
  1466. {
  1467. $rs = null;
  1468. if($symsize <0 ||$symsize >8) return $rs;
  1469. if($fcr <0 ||$fcr >= (1<<$symsize)) return $rs;
  1470. if($prim <= 0 ||$prim >= (1<<$symsize)) return $rs;
  1471. if($nroots <0 ||$nroots >= (1<<$symsize)) return $rs;
  1472. if($pad <0 ||$pad >= ((1<<$symsize) -1 -$nroots)) return $rs;
  1473. $rs = new QRrsItem();
  1474. $rs->mm = $symsize;
  1475. $rs->nn = (1<<$symsize)-1;
  1476. $rs->pad = $pad;
  1477. $rs->alpha_to = array_fill(0,$rs->nn+1,0);
  1478. $rs->index_of = array_fill(0,$rs->nn+1,0);
  1479. $NN =&$rs->nn;
  1480. $A0 =&$NN;
  1481. $rs->index_of[0] = $A0;
  1482. $rs->alpha_to[$A0] = 0;
  1483. $sr = 1;
  1484. for($i=0;$i<$rs->nn;$i++) {
  1485. $rs->index_of[$sr] = $i;
  1486. $rs->alpha_to[$i] = $sr;
  1487. $sr <<= 1;
  1488. if($sr &(1<<$symsize)) {
  1489. $sr ^= $gfpoly;
  1490. }
  1491. $sr &= $rs->nn;
  1492. }
  1493. if($sr != 1){
  1494. $rs = NULL;
  1495. return $rs;
  1496. }
  1497. $rs->genpoly = array_fill(0,$nroots+1,0);
  1498. $rs->fcr = $fcr;
  1499. $rs->prim = $prim;
  1500. $rs->nroots = $nroots;
  1501. $rs->gfpoly = $gfpoly;
  1502. for($iprim=1;($iprim %$prim) != 0;$iprim += $rs->nn)
  1503. ;
  1504. $rs->iprim = (int)($iprim / $prim);
  1505. $rs->genpoly[0] = 1;
  1506. for ($i = 0,$root=$fcr*$prim;$i <$nroots;$i++,$root += $prim) {
  1507. $rs->genpoly[$i+1] = 1;
  1508. for ($j = $i;$j >0;$j--) {
  1509. if ($rs->genpoly[$j] != 0) {
  1510. $rs->genpoly[$j] = $rs->genpoly[$j-1] ^$rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] +$root)];
  1511. }else {
  1512. $rs->genpoly[$j] = $rs->genpoly[$j-1];
  1513. }
  1514. }
  1515. $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] +$root)];
  1516. }
  1517. for ($i = 0;$i <= $nroots;$i++)
  1518. $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
  1519. return $rs;
  1520. }
  1521. public function encode_rs_char($data,&$parity)
  1522. {
  1523. $MM =&$this->mm;
  1524. $NN =&$this->nn;
  1525. $ALPHA_TO =&$this->alpha_to;
  1526. $INDEX_OF =&$this->index_of;
  1527. $GENPOLY =&$this->genpoly;
  1528. $NROOTS =&$this->nroots;
  1529. $FCR =&$this->fcr;
  1530. $PRIM =&$this->prim;
  1531. $IPRIM =&$this->iprim;
  1532. $PAD =&$this->pad;
  1533. $A0 =&$NN;
  1534. $parity = array_fill(0,$NROOTS,0);
  1535. for($i=0;$i<($NN-$NROOTS-$PAD);$i++) {
  1536. $feedback = $INDEX_OF[$data[$i] ^$parity[0]];
  1537. if($feedback != $A0) {
  1538. $feedback = $this->modnn($NN -$GENPOLY[$NROOTS] +$feedback);
  1539. for($j=1;$j<$NROOTS;$j++) {
  1540. $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback +$GENPOLY[$NROOTS-$j])];
  1541. }
  1542. }
  1543. array_shift($parity);
  1544. if($feedback != $A0) {
  1545. array_push($parity,$ALPHA_TO[$this->modnn($feedback +$GENPOLY[0])]);
  1546. }else {
  1547. array_push($parity,0);
  1548. }
  1549. }
  1550. }
  1551. }
  1552. class QRrs {
  1553. public static $items = array();
  1554. public static function init_rs($symsize,$gfpoly,$fcr,$prim,$nroots,$pad)
  1555. {
  1556. foreach(self::$items as $rs) {
  1557. if($rs->pad != $pad) continue;
  1558. if($rs->nroots != $nroots) continue;
  1559. if($rs->mm != $symsize) continue;
  1560. if($rs->gfpoly != $gfpoly) continue;
  1561. if($rs->fcr != $fcr) continue;
  1562. if($rs->prim != $prim) continue;
  1563. return $rs;
  1564. }
  1565. $rs = QRrsItem::init_rs_char($symsize,$gfpoly,$fcr,$prim,$nroots,$pad);
  1566. array_unshift(self::$items,$rs);
  1567. return $rs;
  1568. }
  1569. }
  1570. define('N1',3);
  1571. define('N2',3);
  1572. define('N3',40);
  1573. define('N4',10);
  1574. class QRmask {
  1575. public $runLength = array();
  1576. public function __construct()
  1577. {
  1578. $this->runLength = array_fill(0,QRSPEC_WIDTH_MAX +1,0);
  1579. }
  1580. public function writeFormatInformation($width,&$frame,$mask,$level)
  1581. {
  1582. $blacks = 0;
  1583. $format = QRspec::getFormatInfo($mask,$level);
  1584. for($i=0;$i<8;$i++) {
  1585. if($format &1) {
  1586. $blacks += 2;
  1587. $v = 0x85;
  1588. }else {
  1589. $v = 0x84;
  1590. }
  1591. $frame[8][$width -1 -$i] = chr($v);
  1592. if($i <6) {
  1593. $frame[$i][8] = chr($v);
  1594. }else {
  1595. $frame[$i +1][8] = chr($v);
  1596. }
  1597. $format = $format >>1;
  1598. }
  1599. for($i=0;$i<7;$i++) {
  1600. if($format &1) {
  1601. $blacks += 2;
  1602. $v = 0x85;
  1603. }else {
  1604. $v = 0x84;
  1605. }
  1606. $frame[$width -7 +$i][8] = chr($v);
  1607. if($i == 0) {
  1608. $frame[8][7] = chr($v);
  1609. }else {
  1610. $frame[8][6 -$i] = chr($v);
  1611. }
  1612. $format = $format >>1;
  1613. }
  1614. return $blacks;
  1615. }
  1616. public function mask0($x,$y) {return ($x+$y)&1;}
  1617. public function mask1($x,$y) {return ($y&1);}
  1618. public function mask2($x,$y) {return ($x%3);}
  1619. public function mask3($x,$y) {return ($x+$y)%3;}
  1620. public function mask4($x,$y) {return (((int)($y/2))+((int)($x/3)))&1;}
  1621. public function mask5($x,$y) {return (($x*$y)&1)+($x*$y)%3;}
  1622. public function mask6($x,$y) {return ((($x*$y)&1)+($x*$y)%3)&1;}
  1623. public function mask7($x,$y) {return ((($x*$y)%3)+(($x+$y)&1))&1;}
  1624. private function generateMaskNo($maskNo,$width,$frame)
  1625. {
  1626. $bitMask = array_fill(0,$width,array_fill(0,$width,0));
  1627. for($y=0;$y<$width;$y++) {
  1628. for($x=0;$x<$width;$x++) {
  1629. if(ord($frame[$y][$x]) &0x80) {
  1630. $bitMask[$y][$x] = 0;
  1631. }else {
  1632. $maskFunc = call_user_func(array($this,'mask'.$maskNo),$x,$y);
  1633. $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
  1634. }
  1635. }
  1636. }
  1637. return $bitMask;
  1638. }
  1639. public static function serial($bitFrame)
  1640. {
  1641. $codeArr = array();
  1642. foreach ($bitFrame as $line)
  1643. $codeArr[] = join('',$line);
  1644. return gzcompress(join("\n",$codeArr),9);
  1645. }
  1646. public static function unserial($code)
  1647. {
  1648. $codeArr = array();
  1649. $codeLines = explode("\n",gzuncompress($code));
  1650. foreach ($codeLines as $line)
  1651. $codeArr[] = str_split($line);
  1652. return $codeArr;
  1653. }
  1654. public function makeMaskNo($maskNo,$width,$s,&$d,$maskGenOnly = false)
  1655. {
  1656. $b = 0;
  1657. $bitMask = array();
  1658. $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
  1659. if (QR_CACHEABLE) {
  1660. if (file_exists($fileName)) {
  1661. $bitMask = self::unserial(file_get_contents($fileName));
  1662. }else {
  1663. $bitMask = $this->generateMaskNo($maskNo,$width,$s,$d);
  1664. if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
  1665. mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
  1666. file_put_contents($fileName,self::serial($bitMask));
  1667. }
  1668. }else {
  1669. $bitMask = $this->generateMaskNo($maskNo,$width,$s,$d);
  1670. }
  1671. if ($maskGenOnly)
  1672. return;
  1673. $d = $s;
  1674. for($y=0;$y<$width;$y++) {
  1675. for($x=0;$x<$width;$x++) {
  1676. if($bitMask[$y][$x] == 1) {
  1677. $d[$y][$x] = chr(ord($s[$y][$x]) ^(int)$bitMask[$y][$x]);
  1678. }
  1679. $b += (int)(ord($d[$y][$x]) &1);
  1680. }
  1681. }
  1682. return $b;
  1683. }
  1684. public function makeMask($width,$frame,$maskNo,$level)
  1685. {
  1686. $masked = array_fill(0,$width,str_repeat("\0",$width));
  1687. $this->makeMaskNo($maskNo,$width,$frame,$masked);
  1688. $this->writeFormatInformation($width,$masked,$maskNo,$level);
  1689. return $masked;
  1690. }
  1691. public function calcN1N3($length)
  1692. {
  1693. $demerit = 0;
  1694. for($i=0;$i<$length;$i++) {
  1695. if($this->runLength[$i] >= 5) {
  1696. $demerit += (N1 +($this->runLength[$i] -5));
  1697. }
  1698. if($i &1) {
  1699. if(($i >= 3) &&($i <($length-2)) &&($this->runLength[$i] %3 == 0)) {
  1700. $fact = (int)($this->runLength[$i] / 3);
  1701. if(($this->runLength[$i-2] == $fact) &&
  1702. ($this->runLength[$i-1] == $fact) &&
  1703. ($this->runLength[$i+1] == $fact) &&
  1704. ($this->runLength[$i+2] == $fact)) {
  1705. if(($this->runLength[$i-3] <0) ||($this->runLength[$i-3] >= (4 * $fact))) {
  1706. $demerit += N3;
  1707. }else if((($i+3) >= $length) ||($this->runLength[$i+3] >= (4 * $fact))) {
  1708. $demerit += N3;
  1709. }
  1710. }
  1711. }
  1712. }
  1713. }
  1714. return $demerit;
  1715. }
  1716. public function evaluateSymbol($width,$frame)
  1717. {
  1718. $head = 0;
  1719. $demerit = 0;
  1720. for($y=0;$y<$width;$y++) {
  1721. $head = 0;
  1722. $this->runLength[0] = 1;
  1723. $frameY = $frame[$y];
  1724. if ($y>0)
  1725. $frameYM = $frame[$y-1];
  1726. for($x=0;$x<$width;$x++) {
  1727. if(($x >0) &&($y >0)) {
  1728. $b22 = ord($frameY[$x]) &ord($frameY[$x-1]) &ord($frameYM[$x]) &ord($frameYM[$x-1]);
  1729. $w22 = ord($frameY[$x]) |ord($frameY[$x-1]) |ord($frameYM[$x]) |ord($frameYM[$x-1]);
  1730. if(($b22 |($w22 ^1))&1) {
  1731. $demerit += N2;
  1732. }
  1733. }
  1734. if(($x == 0) &&(ord($frameY[$x]) &1)) {
  1735. $this->runLength[0] = -1;
  1736. $head = 1;
  1737. $this->runLength[$head] = 1;
  1738. }else if($x >0) {
  1739. if((ord($frameY[$x]) ^ord($frameY[$x-1])) &1) {
  1740. $head++;
  1741. $this->runLength[$head] = 1;
  1742. }else {
  1743. $this->runLength[$head]++;
  1744. }
  1745. }
  1746. }
  1747. $demerit += $this->calcN1N3($head+1);
  1748. }
  1749. for($x=0;$x<$width;$x++) {
  1750. $head = 0;
  1751. $this->runLength[0] = 1;
  1752. for($y=0;$y<$width;$y++) {
  1753. if($y == 0 &&(ord($frame[$y][$x]) &1)) {
  1754. $this->runLength[0] = -1;
  1755. $head = 1;
  1756. $this->runLength[$head] = 1;
  1757. }else if($y >0) {
  1758. if((ord($frame[$y][$x]) ^ord($frame[$y-1][$x])) &1) {
  1759. $head++;
  1760. $this->runLength[$head] = 1;
  1761. }else {
  1762. $this->runLength[$head]++;
  1763. }
  1764. }
  1765. }
  1766. $demerit += $this->calcN1N3($head+1);
  1767. }
  1768. return $demerit;
  1769. }
  1770. public function mask($width,$frame,$level)
  1771. {
  1772. $minDemerit = PHP_INT_MAX;
  1773. $bestMaskNum = 0;
  1774. $bestMask = array();
  1775. $checked_masks = array(0,1,2,3,4,5,6,7);
  1776. if (QR_FIND_FROM_RANDOM !== false) {
  1777. $howManuOut = 8-(QR_FIND_FROM_RANDOM %9);
  1778. for ($i = 0;$i <$howManuOut;$i++) {
  1779. $remPos = rand (0,count($checked_masks)-1);
  1780. unset($checked_masks[$remPos]);
  1781. $checked_masks = array_values($checked_masks);
  1782. }
  1783. }
  1784. $bestMask = $frame;
  1785. foreach($checked_masks as $i) {
  1786. $mask = array_fill(0,$width,str_repeat("\0",$width));
  1787. $demerit = 0;
  1788. $blacks = 0;
  1789. $blacks = $this->makeMaskNo($i,$width,$frame,$mask);
  1790. $blacks += $this->writeFormatInformation($width,$mask,$i,$level);
  1791. $blacks = (int)(100 * $blacks / ($width * $width));
  1792. $demerit = (int)((int)(abs($blacks -50) / 5) * N4);
  1793. $demerit += $this->evaluateSymbol($width,$mask);
  1794. if($demerit <$minDemerit) {
  1795. $minDemerit = $demerit;
  1796. $bestMask = $mask;
  1797. $bestMaskNum = $i;
  1798. }
  1799. }
  1800. return $bestMask;
  1801. }
  1802. }
  1803. class QRrsblock {
  1804. public $dataLength;
  1805. public $data = array();
  1806. public $eccLength;
  1807. public $ecc = array();
  1808. public function __construct($dl,$data,$el,&$ecc,QRrsItem $rs)
  1809. {
  1810. $rs->encode_rs_char($data,$ecc);
  1811. $this->dataLength = $dl;
  1812. $this->data = $data;
  1813. $this->eccLength = $el;
  1814. $this->ecc = $ecc;
  1815. }
  1816. };
  1817. class QRrawcode {
  1818. public $version;
  1819. public $datacode = array();
  1820. public $ecccode = array();
  1821. public $blocks;
  1822. public $rsblocks = array();
  1823. public $count;
  1824. public $dataLength;
  1825. public $eccLength;
  1826. public $b1;
  1827. public function __construct(QRinput $input)
  1828. {
  1829. $spec = array(0,0,0,0,0);
  1830. $this->datacode = $input->getByteStream();
  1831. if(is_null($this->datacode)) {
  1832. throw new Exception('null imput string');
  1833. }
  1834. QRspec::getEccSpec($input->getVersion(),$input->getErrorCorrectionLevel(),$spec);
  1835. $this->version = $input->getVersion();
  1836. $this->b1 = QRspec::rsBlockNum1($spec);
  1837. $this->dataLength = QRspec::rsDataLength($spec);
  1838. $this->eccLength = QRspec::rsEccLength($spec);
  1839. $this->ecccode = array_fill(0,$this->eccLength,0);
  1840. $this->blocks = QRspec::rsBlockNum($spec);
  1841. $ret = $this->init($spec);
  1842. if($ret <0) {
  1843. throw new Exception('block alloc error');
  1844. return null;
  1845. }
  1846. $this->count = 0;
  1847. }
  1848. public function init(array $spec)
  1849. {
  1850. $dl = QRspec::rsDataCodes1($spec);
  1851. $el = QRspec::rsEccCodes1($spec);
  1852. $rs = QRrs::init_rs(8,0x11d,0,1,$el,255 -$dl -$el);
  1853. $blockNo = 0;
  1854. $dataPos = 0;
  1855. $eccPos = 0;
  1856. for($i=0;$i<QRspec::rsBlockNum1($spec);$i++) {
  1857. $ecc = array_slice($this->ecccode,$eccPos);
  1858. $this->rsblocks[$blockNo] = new QRrsblock($dl,array_slice($this->datacode,$dataPos),$el,$ecc,$rs);
  1859. $this->ecccode = array_merge(array_slice($this->ecccode,0,$eccPos),$ecc);
  1860. $dataPos += $dl;
  1861. $eccPos += $el;
  1862. $blockNo++;
  1863. }
  1864. if(QRspec::rsBlockNum2($spec) == 0)
  1865. return 0;
  1866. $dl = QRspec::rsDataCodes2($spec);
  1867. $el = QRspec::rsEccCodes2($spec);
  1868. $rs = QRrs::init_rs(8,0x11d,0,1,$el,255 -$dl -$el);
  1869. if($rs == NULL) return -1;
  1870. for($i=0;$i<QRspec::rsBlockNum2($spec);$i++) {
  1871. $ecc = array_slice($this->ecccode,$eccPos);
  1872. $this->rsblocks[$blockNo] = new QRrsblock($dl,array_slice($this->datacode,$dataPos),$el,$ecc,$rs);
  1873. $this->ecccode = array_merge(array_slice($this->ecccode,0,$eccPos),$ecc);
  1874. $dataPos += $dl;
  1875. $eccPos += $el;
  1876. $blockNo++;
  1877. }
  1878. return 0;
  1879. }
  1880. public function getCode()
  1881. {
  1882. $ret;
  1883. if($this->count <$this->dataLength) {
  1884. $row = $this->count %$this->blocks;
  1885. $col = $this->count / $this->blocks;
  1886. if($col >= $this->rsblocks[0]->dataLength) {
  1887. $row += $this->b1;
  1888. }
  1889. $ret = $this->rsblocks[$row]->data[$col];
  1890. }else if($this->count <$this->dataLength +$this->eccLength) {
  1891. $row = ($this->count -$this->dataLength) %$this->blocks;
  1892. $col = ($this->count -$this->dataLength) / $this->blocks;
  1893. $ret = $this->rsblocks[$row]->ecc[$col];
  1894. }else {
  1895. return 0;
  1896. }
  1897. $this->count++;
  1898. return $ret;
  1899. }
  1900. }
  1901. class QRcode {
  1902. public $version;
  1903. public $width;
  1904. public $data;
  1905. public function encodeMask(QRinput $input,$mask)
  1906. {
  1907. if($input->getVersion() <0 ||$input->getVersion() >QRSPEC_VERSION_MAX) {
  1908. throw new Exception('wrong version');
  1909. }
  1910. if($input->getErrorCorrectionLevel() >QR_ECLEVEL_H) {
  1911. throw new Exception('wrong level');
  1912. }
  1913. $raw = new QRrawcode($input);
  1914. QRtools::markTime('after_raw');
  1915. $version = $raw->version;
  1916. $width = QRspec::getWidth($version);
  1917. $frame = QRspec::newFrame($version);
  1918. $filler = new FrameFiller($width,$frame);
  1919. if(is_null($filler)) {
  1920. return NULL;
  1921. }
  1922. for($i=0;$i<$raw->dataLength +$raw->eccLength;$i++) {
  1923. $code = $raw->getCode();
  1924. $bit = 0x80;
  1925. for($j=0;$j<8;$j++) {
  1926. $addr = $filler->next();
  1927. $filler->setFrameAt($addr,0x02 |(($bit &$code) != 0));
  1928. $bit = $bit >>1;
  1929. }
  1930. }
  1931. QRtools::markTime('after_filler');
  1932. unset($raw);
  1933. $j = QRspec::getRemainder($version);
  1934. for($i=0;$i<$j;$i++) {
  1935. $addr = $filler->next();
  1936. $filler->setFrameAt($addr,0x02);
  1937. }
  1938. $frame = $filler->frame;
  1939. unset($filler);
  1940. $maskObj = new QRmask();
  1941. if($mask <0) {
  1942. if (QR_FIND_BEST_MASK) {
  1943. $masked = $maskObj->mask($width,$frame,$input->getErrorCorrectionLevel());
  1944. }else {
  1945. $masked = $maskObj->makeMask($width,$frame,(intval(QR_DEFAULT_MASK) %8),$input->getErrorCorrectionLevel());
  1946. }
  1947. }else {
  1948. $masked = $maskObj->makeMask($width,$frame,$mask,$input->getErrorCorrectionLevel());
  1949. }
  1950. if($masked == NULL) {
  1951. return NULL;
  1952. }
  1953. QRtools::markTime('after_mask');
  1954. $this->version = $version;
  1955. $this->width = $width;
  1956. $this->data = $masked;
  1957. return $this;
  1958. }
  1959. public function encodeInput(QRinput $input)
  1960. {
  1961. return $this->encodeMask($input,-1);
  1962. }
  1963. public function encodeString8bit($string,$version,$level)
  1964. {
  1965. if(string == NULL) {
  1966. throw new Exception('empty string!');
  1967. return NULL;
  1968. }
  1969. $input = new QRinput($version,$level);
  1970. if($input == NULL) return NULL;
  1971. $ret = $input->append($input,QR_MODE_8,strlen($string),str_split($string));
  1972. if($ret <0) {
  1973. unset($input);
  1974. return NULL;
  1975. }
  1976. return $this->encodeInput($input);
  1977. }
  1978. public function encodeString($string,$version,$level,$hint,$casesensitive)
  1979. {
  1980. if($hint != QR_MODE_8 &&$hint != QR_MODE_KANJI) {
  1981. throw new Exception('bad hint');
  1982. return NULL;
  1983. }
  1984. $input = new QRinput($version,$level);
  1985. if($input == NULL) return NULL;
  1986. $ret = QRsplit::splitStringToQRinput($string,$input,$hint,$casesensitive);
  1987. if($ret <0) {
  1988. return NULL;
  1989. }
  1990. return $this->encodeInput($input);
  1991. }
  1992. public static function png($text,$outfile = false,$level = QR_ECLEVEL_L,$size = 3,$margin = 4,$saveandprint=false)
  1993. {
  1994. $enc = QRencode::factory($level,$size,$margin);
  1995. return $enc->encodePNG($text,$outfile,$saveandprint=false);
  1996. }
  1997. public static function text($text,$outfile = false,$level = QR_ECLEVEL_L,$size = 3,$margin = 4)
  1998. {
  1999. $enc = QRencode::factory($level,$size,$margin);
  2000. return $enc->encode($text,$outfile);
  2001. }
  2002. public static function raw($text,$outfile = false,$level = QR_ECLEVEL_L,$size = 3,$margin = 4)
  2003. {
  2004. $enc = QRencode::factory($level,$size,$margin);
  2005. return $enc->encodeRAW($text,$outfile);
  2006. }
  2007. }
  2008. class FrameFiller {
  2009. public $width;
  2010. public $frame;
  2011. public $x;
  2012. public $y;
  2013. public $dir;
  2014. public $bit;
  2015. public function __construct($width,&$frame)
  2016. {
  2017. $this->width = $width;
  2018. $this->frame = $frame;
  2019. $this->x = $width -1;
  2020. $this->y = $width -1;
  2021. $this->dir = -1;
  2022. $this->bit = -1;
  2023. }
  2024. public function setFrameAt($at,$val)
  2025. {
  2026. $this->frame[$at['y']][$at['x']] = chr($val);
  2027. }
  2028. public function getFrameAt($at)
  2029. {
  2030. return ord($this->frame[$at['y']][$at['x']]);
  2031. }
  2032. public function next()
  2033. {
  2034. do {
  2035. if($this->bit == -1) {
  2036. $this->bit = 0;
  2037. return array('x'=>$this->x,'y'=>$this->y);
  2038. }
  2039. $x = $this->x;
  2040. $y = $this->y;
  2041. $w = $this->width;
  2042. if($this->bit == 0) {
  2043. $x--;
  2044. $this->bit++;
  2045. }else {
  2046. $x++;
  2047. $y += $this->dir;
  2048. $this->bit--;
  2049. }
  2050. if($this->dir <0) {
  2051. if($y <0) {
  2052. $y = 0;
  2053. $x -= 2;
  2054. $this->dir = 1;
  2055. if($x == 6) {
  2056. $x--;
  2057. $y = 9;
  2058. }
  2059. }
  2060. }else {
  2061. if($y == $w) {
  2062. $y = $w -1;
  2063. $x -= 2;
  2064. $this->dir = -1;
  2065. if($x == 6) {
  2066. $x--;
  2067. $y -= 8;
  2068. }
  2069. }
  2070. }
  2071. if($x <0 ||$y <0) return null;
  2072. $this->x = $x;
  2073. $this->y = $y;
  2074. }while(ord($this->frame[$y][$x]) &0x80);
  2075. return array('x'=>$x,'y'=>$y);
  2076. }
  2077. };
  2078. class QRencode {
  2079. public $casesensitive = true;
  2080. public $eightbit = false;
  2081. public $version = 0;
  2082. public $size = 3;
  2083. public $margin = 4;
  2084. public $structured = 0;
  2085. public $level = QR_ECLEVEL_L;
  2086. public $hint = QR_MODE_8;
  2087. public static function factory($level = QR_ECLEVEL_L,$size = 3,$margin = 4)
  2088. {
  2089. $enc = new QRencode();
  2090. $enc->size = $size;
  2091. $enc->margin = $margin;
  2092. switch ($level.'') {
  2093. case '0':
  2094. case '1':
  2095. case '2':
  2096. case '3':
  2097. $enc->level = $level;
  2098. break;
  2099. case 'l':
  2100. case 'L':
  2101. $enc->level = QR_ECLEVEL_L;
  2102. break;
  2103. case 'm':
  2104. case 'M':
  2105. $enc->level = QR_ECLEVEL_M;
  2106. break;
  2107. case 'q':
  2108. case 'Q':
  2109. $enc->level = QR_ECLEVEL_Q;
  2110. break;
  2111. case 'h':
  2112. case 'H':
  2113. $enc->level = QR_ECLEVEL_H;
  2114. break;
  2115. }
  2116. return $enc;
  2117. }
  2118. public function encodeRAW($intext,$outfile = false)
  2119. {
  2120. $code = new QRcode();
  2121. if($this->eightbit) {
  2122. $code->encodeString8bit($intext,$this->version,$this->level);
  2123. }else {
  2124. $code->encodeString($intext,$this->version,$this->level,$this->hint,$this->casesensitive);
  2125. }
  2126. return $code->data;
  2127. }
  2128. public function encode($intext,$outfile = false)
  2129. {
  2130. $code = new QRcode();
  2131. if($this->eightbit) {
  2132. $code->encodeString8bit($intext,$this->version,$this->level);
  2133. }else {
  2134. $code->encodeString($intext,$this->version,$this->level,$this->hint,$this->casesensitive);
  2135. }
  2136. QRtools::markTime('after_encode');
  2137. if ($outfile!== false) {
  2138. file_put_contents($outfile,join("\n",QRtools::binarize($code->data)));
  2139. }else {
  2140. return QRtools::binarize($code->data);
  2141. }
  2142. }
  2143. public function encodePNG($intext,$outfile = false,$saveandprint=false)
  2144. {
  2145. try {
  2146. ob_start();
  2147. $tab = $this->encode($intext);
  2148. $err = ob_get_contents();
  2149. ob_end_clean();
  2150. if ($err != '')
  2151. QRtools::log($outfile,$err);
  2152. $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
  2153. QRimage::png($tab,$outfile,min(max(1,$this->size),$maxSize),$this->margin,$saveandprint);
  2154. }catch (Exception $e) {
  2155. QRtools::log($outfile,$e->getMessage());
  2156. }
  2157. }
  2158. }
  2159. echo QRcode::png(isset($_GET['link']) ?$_GET['link'] : NULL);
  2160. ?>