PageRenderTime 67ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/qrcode.php

https://github.com/felipegirotti/2D-3D-Barcodes-Generator
PHP | 2784 lines | 1696 code | 208 blank | 880 comment | 296 complexity | 1a7f31eb39555580106a24dd15c22fbb MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. //============================================================+
  3. // File name : qrcode.php
  4. // Author : Dinesh Rabara
  5. /**
  6. * @author Dinesh Rabara
  7. * @version 1.0.009
  8. */
  9. // definitions
  10. if (!defined('QRCODEDEFS')) {
  11. /**
  12. * Indicate that definitions for this class are set
  13. */
  14. define('QRCODEDEFS', true);
  15. // -----------------------------------------------------
  16. // Encoding modes (characters which can be encoded in QRcode)
  17. /**
  18. * Encoding mode
  19. */
  20. define('QR_MODE_NL', -1);
  21. /**
  22. * Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode.
  23. */
  24. define('QR_MODE_NM', 0);
  25. /**
  26. * Encoding mode alphanumeric (0-9A-Z $%*+-./:) 45characters. 2 characters are encoded to 11bit length. In theory, 4296 characters or less can be stored in a QRcode.
  27. */
  28. define('QR_MODE_AN', 1);
  29. /**
  30. * Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
  31. */
  32. define('QR_MODE_8B', 2);
  33. /**
  34. * Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length. In theory, 1817 characters or less can be stored in a QRcode.
  35. */
  36. define('QR_MODE_KJ', 3);
  37. /**
  38. * Encoding mode STRUCTURED (currently unsupported)
  39. */
  40. define('QR_MODE_ST', 4);
  41. // -----------------------------------------------------
  42. // Levels of error correction.
  43. // QRcode has a function of an error correcting for miss reading that white is black.
  44. // Error correcting is defined in 4 level as below.
  45. /**
  46. * Error correction level L : About 7% or less errors can be corrected.
  47. */
  48. define('QR_ECLEVEL_L', 0);
  49. /**
  50. * Error correction level M : About 15% or less errors can be corrected.
  51. */
  52. define('QR_ECLEVEL_M', 1);
  53. /**
  54. * Error correction level Q : About 25% or less errors can be corrected.
  55. */
  56. define('QR_ECLEVEL_Q', 2);
  57. /**
  58. * Error correction level H : About 30% or less errors can be corrected.
  59. */
  60. define('QR_ECLEVEL_H', 3);
  61. // -----------------------------------------------------
  62. // Version. Size of QRcode is defined as version.
  63. // Version is from 1 to 40.
  64. // Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
  65. // So version 40 is 177*177 matrix.
  66. /**
  67. * Maximum QR Code version.
  68. */
  69. define('QRSPEC_VERSION_MAX', 40);
  70. /**
  71. * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
  72. */
  73. define('QRSPEC_WIDTH_MAX', 177);
  74. // -----------------------------------------------------
  75. /**
  76. * Matrix index to get width from $capacity array.
  77. */
  78. define('QRCAP_WIDTH', 0);
  79. /**
  80. * Matrix index to get number of words from $capacity array.
  81. */
  82. define('QRCAP_WORDS', 1);
  83. /**
  84. * Matrix index to get remainder from $capacity array.
  85. */
  86. define('QRCAP_REMINDER', 2);
  87. /**
  88. * Matrix index to get error correction level from $capacity array.
  89. */
  90. define('QRCAP_EC', 3);
  91. // -----------------------------------------------------
  92. // Structure (currently usupported)
  93. /**
  94. * Number of header bits for structured mode
  95. */
  96. define('STRUCTURE_HEADER_BITS', 20);
  97. /**
  98. * Max number of symbols for structured mode
  99. */
  100. define('MAX_STRUCTURED_SYMBOLS', 16);
  101. // -----------------------------------------------------
  102. // Masks
  103. /**
  104. * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
  105. */
  106. define('N1', 3);
  107. /**
  108. * Down point base value for case 2 mask pattern (module block of same color)
  109. */
  110. define('N2', 3);
  111. /**
  112. * Down point base value for case 3 mask pattern (1:1:3:1:1(dark:bright:dark:bright:dark)pattern in a line or a column)
  113. */
  114. define('N3', 40);
  115. /**
  116. * Down point base value for case 4 mask pattern (ration of dark modules in whole)
  117. */
  118. define('N4', 10);
  119. // -----------------------------------------------------
  120. // Optimization settings
  121. /**
  122. * if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
  123. */
  124. define('QR_FIND_BEST_MASK', true);
  125. /**
  126. * if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
  127. */
  128. define('QR_FIND_FROM_RANDOM', 2);
  129. /**
  130. * when QR_FIND_BEST_MASK === false
  131. */
  132. define('QR_DEFAULT_MASK', 2);
  133. // -----------------------------------------------------
  134. } // end of definitions
  135. // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
  136. // for compatibility with PHP4
  137. if (!function_exists('str_split')) {
  138. /**
  139. * Convert a string to an array (needed for PHP4 compatibility)
  140. * @param $string (string) The input string.
  141. * @param $split_length (int) Maximum length of the chunk.
  142. * @return If the optional split_length parameter is specified, the returned array will be broken down into chunks with each being split_length in length, otherwise each chunk will be one character in length. FALSE is returned if split_length is less than 1. If the split_length length exceeds the length of string , the entire string is returned as the first (and only) array element.
  143. */
  144. function str_split($string, $split_length=1) {
  145. if ((strlen($string) > $split_length) OR (!$split_length)) {
  146. do {
  147. $c = strlen($string);
  148. $parts[] = substr($string, 0, $split_length);
  149. $string = substr($string, $split_length);
  150. } while ($string !== false);
  151. } else {
  152. $parts = array($string);
  153. }
  154. return $parts;
  155. }
  156. }
  157. // #####################################################
  158. /**
  159. * @author Dinesh Rabara
  160. * @version 1.0.009
  161. */
  162. class QRcode {
  163. /**
  164. * Barcode array to be returned which is readable by Dinesh Rabara.
  165. * @protected
  166. */
  167. protected $barcode_array = array();
  168. /**
  169. * QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix.
  170. * @protected
  171. */
  172. protected $version = 0;
  173. /**
  174. * Levels of error correction. See definitions for possible values.
  175. * @protected
  176. */
  177. protected $level = QR_ECLEVEL_L;
  178. /**
  179. * Encoding mode.
  180. * @protected
  181. */
  182. protected $hint = QR_MODE_8B;
  183. /**
  184. * Boolean flag, if true the input string will be converted to uppercase.
  185. * @protected
  186. */
  187. protected $casesensitive = true;
  188. /**
  189. * Structured QR code (not supported yet).
  190. * @protected
  191. */
  192. protected $structured = 0;
  193. /**
  194. * Mask data.
  195. * @protected
  196. */
  197. protected $data;
  198. // FrameFiller
  199. /**
  200. * Width.
  201. * @protected
  202. */
  203. protected $width;
  204. /**
  205. * Frame.
  206. * @protected
  207. */
  208. protected $frame;
  209. /**
  210. * X position of bit.
  211. * @protected
  212. */
  213. protected $x;
  214. /**
  215. * Y position of bit.
  216. * @protected
  217. */
  218. protected $y;
  219. /**
  220. * Direction.
  221. * @protected
  222. */
  223. protected $dir;
  224. /**
  225. * Single bit value.
  226. * @protected
  227. */
  228. protected $bit;
  229. // ---- QRrawcode ----
  230. /**
  231. * Data code.
  232. * @protected
  233. */
  234. protected $datacode = array();
  235. /**
  236. * Error correction code.
  237. * @protected
  238. */
  239. protected $ecccode = array();
  240. /**
  241. * Blocks.
  242. * @protected
  243. */
  244. protected $blocks;
  245. /**
  246. * Reed-Solomon blocks.
  247. * @protected
  248. */
  249. protected $rsblocks = array(); //of RSblock
  250. /**
  251. * Counter.
  252. * @protected
  253. */
  254. protected $count;
  255. /**
  256. * Data length.
  257. * @protected
  258. */
  259. protected $dataLength;
  260. /**
  261. * Error correction length.
  262. * @protected
  263. */
  264. protected $eccLength;
  265. /**
  266. * Value b1.
  267. * @protected
  268. */
  269. protected $b1;
  270. // ---- QRmask ----
  271. /**
  272. * Run length.
  273. * @protected
  274. */
  275. protected $runLength = array();
  276. // ---- QRsplit ----
  277. /**
  278. * Input data string.
  279. * @protected
  280. */
  281. protected $dataStr = '';
  282. /**
  283. * Input items.
  284. * @protected
  285. */
  286. protected $items;
  287. // Reed-Solomon items
  288. /**
  289. * Reed-Solomon items.
  290. * @protected
  291. */
  292. protected $rsitems = array();
  293. /**
  294. * Array of frames.
  295. * @protected
  296. */
  297. protected $frames = array();
  298. /**
  299. * Alphabet-numeric convesion table.
  300. * @protected
  301. */
  302. protected $anTable = array(
  303. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
  304. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
  305. 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
  306. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, //
  307. -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
  308. 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
  309. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
  310. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 //
  311. );
  312. /**
  313. * Array Table of the capacity of symbols.
  314. * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
  315. * @protected
  316. */
  317. protected $capacity = array(
  318. array( 0, 0, 0, array( 0, 0, 0, 0)), //
  319. array( 21, 26, 0, array( 7, 10, 13, 17)), // 1
  320. array( 25, 44, 7, array( 10, 16, 22, 28)), //
  321. array( 29, 70, 7, array( 15, 26, 36, 44)), //
  322. array( 33, 100, 7, array( 20, 36, 52, 64)), //
  323. array( 37, 134, 7, array( 26, 48, 72, 88)), // 5
  324. array( 41, 172, 7, array( 36, 64, 96, 112)), //
  325. array( 45, 196, 0, array( 40, 72, 108, 130)), //
  326. array( 49, 242, 0, array( 48, 88, 132, 156)), //
  327. array( 53, 292, 0, array( 60, 110, 160, 192)), //
  328. array( 57, 346, 0, array( 72, 130, 192, 224)), // 10
  329. array( 61, 404, 0, array( 80, 150, 224, 264)), //
  330. array( 65, 466, 0, array( 96, 176, 260, 308)), //
  331. array( 69, 532, 0, array( 104, 198, 288, 352)), //
  332. array( 73, 581, 3, array( 120, 216, 320, 384)), //
  333. array( 77, 655, 3, array( 132, 240, 360, 432)), // 15
  334. array( 81, 733, 3, array( 144, 280, 408, 480)), //
  335. array( 85, 815, 3, array( 168, 308, 448, 532)), //
  336. array( 89, 901, 3, array( 180, 338, 504, 588)), //
  337. array( 93, 991, 3, array( 196, 364, 546, 650)), //
  338. array( 97, 1085, 3, array( 224, 416, 600, 700)), // 20
  339. array(101, 1156, 4, array( 224, 442, 644, 750)), //
  340. array(105, 1258, 4, array( 252, 476, 690, 816)), //
  341. array(109, 1364, 4, array( 270, 504, 750, 900)), //
  342. array(113, 1474, 4, array( 300, 560, 810, 960)), //
  343. array(117, 1588, 4, array( 312, 588, 870, 1050)), // 25
  344. array(121, 1706, 4, array( 336, 644, 952, 1110)), //
  345. array(125, 1828, 4, array( 360, 700, 1020, 1200)), //
  346. array(129, 1921, 3, array( 390, 728, 1050, 1260)), //
  347. array(133, 2051, 3, array( 420, 784, 1140, 1350)), //
  348. array(137, 2185, 3, array( 450, 812, 1200, 1440)), // 30
  349. array(141, 2323, 3, array( 480, 868, 1290, 1530)), //
  350. array(145, 2465, 3, array( 510, 924, 1350, 1620)), //
  351. array(149, 2611, 3, array( 540, 980, 1440, 1710)), //
  352. array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
  353. array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
  354. array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
  355. array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
  356. array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
  357. array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
  358. array(177, 3706, 0, array( 750, 1372, 2040, 2430)) // 40
  359. );
  360. /**
  361. * Array Length indicator.
  362. * @protected
  363. */
  364. protected $lengthTableBits = array(
  365. array(10, 12, 14),
  366. array( 9, 11, 13),
  367. array( 8, 16, 16),
  368. array( 8, 10, 12)
  369. );
  370. /**
  371. * Array Table of the error correction code (Reed-Solomon block).
  372. * See Table 12-16 (pp.30-36), JIS X0510:2004.
  373. * @protected
  374. */
  375. protected $eccTable = array(
  376. array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), //
  377. array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1
  378. array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), //
  379. array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)), //
  380. array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)), //
  381. array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5
  382. array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)), //
  383. array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)), //
  384. array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)), //
  385. array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)), //
  386. array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), // 10
  387. array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)), //
  388. array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)), //
  389. array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)), //
  390. array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)), //
  391. array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), // 15
  392. array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)), //
  393. array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)), //
  394. array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)), //
  395. array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)), //
  396. array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), // 20
  397. array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)), //
  398. array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)), //
  399. array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)), //
  400. array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)), //
  401. array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
  402. array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), //
  403. array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)), //
  404. array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
  405. array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)), //
  406. array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
  407. array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)), //
  408. array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), //
  409. array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), //
  410. array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), //
  411. array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), // 35
  412. array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
  413. array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), //
  414. array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
  415. array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), //
  416. array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)) // 40
  417. );
  418. /**
  419. * Array Positions of alignment patterns.
  420. * This array includes only the second and the third position of the alignment patterns. Rest of them can be calculated from the distance between them.
  421. * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
  422. * @protected
  423. */
  424. protected $alignmentPattern = array(
  425. array( 0, 0),
  426. array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
  427. array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
  428. array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
  429. array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
  430. array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
  431. array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
  432. array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
  433. array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58) // 35-40
  434. );
  435. /**
  436. * Array Version information pattern (BCH coded).
  437. * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
  438. * size: [QRSPEC_VERSION_MAX - 6]
  439. * @protected
  440. */
  441. protected $versionPattern = array(
  442. 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
  443. 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
  444. 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
  445. 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
  446. 0x27541, 0x28c69
  447. );
  448. /**
  449. * Array Format information
  450. * @protected
  451. */
  452. protected $formatInfo = array(
  453. array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
  454. array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
  455. array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
  456. array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) //
  457. );
  458. // -------------------------------------------------
  459. // -------------------------------------------------
  460. /**
  461. * This is the class constructor.
  462. * Creates a QRcode object
  463. * @param $code (string) code to represent using QRcode
  464. * @param $eclevel (string) error level: <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
  465. * @public
  466. * @since 1.0.000
  467. */
  468. public function __construct($code, $eclevel = 'L') {
  469. $barcode_array = array();
  470. if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
  471. return false;
  472. }
  473. // set error correction level
  474. $this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
  475. if ($this->level === false) {
  476. $this->level = QR_ECLEVEL_L;
  477. }
  478. if (($this->hint != QR_MODE_8B) AND ($this->hint != QR_MODE_KJ)) {
  479. return false;
  480. }
  481. if (($this->version < 0) OR ($this->version > QRSPEC_VERSION_MAX)) {
  482. return false;
  483. }
  484. $this->items = array();
  485. $this->encodeString($code);
  486. if (is_null($this->data)) {
  487. return false;
  488. }
  489. $qrTab = $this->binarize($this->data);
  490. $size = count($qrTab);
  491. $barcode_array['num_rows'] = $size;
  492. $barcode_array['num_cols'] = $size;
  493. $barcode_array['bcode'] = array();
  494. foreach ($qrTab as $line) {
  495. $arrAdd = array();
  496. foreach (str_split($line) as $char) {
  497. $arrAdd[] = ($char=='1')?1:0;
  498. }
  499. $barcode_array['bcode'][] = $arrAdd;
  500. }
  501. $this->barcode_array = $barcode_array;
  502. }
  503. /**
  504. * Returns a barcode array which is readable by Dinesh Rabara
  505. * @return array barcode array readable by Dinesh Rabara;
  506. * @public
  507. */
  508. public function getBarcodeArray() {
  509. return $this->barcode_array;
  510. }
  511. /**
  512. * Convert the frame in binary form
  513. * @param $frame (array) array to binarize
  514. * @return array frame in binary form
  515. */
  516. protected function binarize($frame) {
  517. $len = count($frame);
  518. // the frame is square (width = height)
  519. foreach ($frame as &$frameLine) {
  520. for ($i=0; $i<$len; $i++) {
  521. $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
  522. }
  523. }
  524. return $frame;
  525. }
  526. /**
  527. * Encode the input string to QR code
  528. * @param $string (string) input string to encode
  529. */
  530. protected function encodeString($string) {
  531. $this->dataStr = $string;
  532. if (!$this->casesensitive) {
  533. $this->toUpper();
  534. }
  535. $ret = $this->splitString();
  536. if ($ret < 0) {
  537. return NULL;
  538. }
  539. $this->encodeMask(-1);
  540. }
  541. /**
  542. * Encode mask
  543. * @param $mask (int) masking mode
  544. */
  545. protected function encodeMask($mask) {
  546. $spec = array(0, 0, 0, 0, 0);
  547. $this->datacode = $this->getByteStream($this->items);
  548. if (is_null($this->datacode)) {
  549. return NULL;
  550. }
  551. $spec = $this->getEccSpec($this->version, $this->level, $spec);
  552. $this->b1 = $this->rsBlockNum1($spec);
  553. $this->dataLength = $this->rsDataLength($spec);
  554. $this->eccLength = $this->rsEccLength($spec);
  555. $this->ecccode = array_fill(0, $this->eccLength, 0);
  556. $this->blocks = $this->rsBlockNum($spec);
  557. $ret = $this->init($spec);
  558. if ($ret < 0) {
  559. return NULL;
  560. }
  561. $this->count = 0;
  562. $this->width = $this->getWidth($this->version);
  563. $this->frame = $this->newFrame($this->version);
  564. $this->x = $this->width - 1;
  565. $this->y = $this->width - 1;
  566. $this->dir = -1;
  567. $this->bit = -1;
  568. // inteleaved data and ecc codes
  569. for ($i=0; $i < ($this->dataLength + $this->eccLength); $i++) {
  570. $code = $this->getCode();
  571. $bit = 0x80;
  572. for ($j=0; $j<8; $j++) {
  573. $addr = $this->getNextPosition();
  574. $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
  575. $bit = $bit >> 1;
  576. }
  577. }
  578. // remainder bits
  579. $j = $this->getRemainder($this->version);
  580. for ($i=0; $i<$j; $i++) {
  581. $addr = $this->getNextPosition();
  582. $this->setFrameAt($addr, 0x02);
  583. }
  584. // masking
  585. $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
  586. if ($mask < 0) {
  587. if (QR_FIND_BEST_MASK) {
  588. $masked = $this->mask($this->width, $this->frame, $this->level);
  589. } else {
  590. $masked = $this->makeMask($this->width, $this->frame, (intval(QR_DEFAULT_MASK) % 8), $this->level);
  591. }
  592. } else {
  593. $masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
  594. }
  595. if ($masked == NULL) {
  596. return NULL;
  597. }
  598. $this->data = $masked;
  599. }
  600. // - - - - - - - - - - - - - - - - - - - - - - - - -
  601. // FrameFiller
  602. /**
  603. * Set frame value at specified position
  604. * @param $at (array) x,y position
  605. * @param $val (int) value of the character to set
  606. */
  607. protected function setFrameAt($at, $val) {
  608. $this->frame[$at['y']][$at['x']] = chr($val);
  609. }
  610. /**
  611. * Get frame value at specified position
  612. * @param $at (array) x,y position
  613. * @return value at specified position
  614. */
  615. protected function getFrameAt($at) {
  616. return ord($this->frame[$at['y']][$at['x']]);
  617. }
  618. /**
  619. * Return the next frame position
  620. * @return array of x,y coordinates
  621. */
  622. protected function getNextPosition() {
  623. do {
  624. if ($this->bit == -1) {
  625. $this->bit = 0;
  626. return array('x'=>$this->x, 'y'=>$this->y);
  627. }
  628. $x = $this->x;
  629. $y = $this->y;
  630. $w = $this->width;
  631. if ($this->bit == 0) {
  632. $x--;
  633. $this->bit++;
  634. } else {
  635. $x++;
  636. $y += $this->dir;
  637. $this->bit--;
  638. }
  639. if ($this->dir < 0) {
  640. if ($y < 0) {
  641. $y = 0;
  642. $x -= 2;
  643. $this->dir = 1;
  644. if ($x == 6) {
  645. $x--;
  646. $y = 9;
  647. }
  648. }
  649. } else {
  650. if ($y == $w) {
  651. $y = $w - 1;
  652. $x -= 2;
  653. $this->dir = -1;
  654. if ($x == 6) {
  655. $x--;
  656. $y -= 8;
  657. }
  658. }
  659. }
  660. if (($x < 0) OR ($y < 0)) {
  661. return NULL;
  662. }
  663. $this->x = $x;
  664. $this->y = $y;
  665. } while(ord($this->frame[$y][$x]) & 0x80);
  666. return array('x'=>$x, 'y'=>$y);
  667. }
  668. // - - - - - - - - - - - - - - - - - - - - - - - - -
  669. // QRrawcode
  670. /**
  671. * Initialize code.
  672. * @param $spec (array) array of ECC specification
  673. * @return 0 in case of success, -1 in case of error
  674. */
  675. protected function init($spec) {
  676. $dl = $this->rsDataCodes1($spec);
  677. $el = $this->rsEccCodes1($spec);
  678. $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
  679. $blockNo = 0;
  680. $dataPos = 0;
  681. $eccPos = 0;
  682. $endfor = $this->rsBlockNum1($spec);
  683. for ($i=0; $i < $endfor; ++$i) {
  684. $ecc = array_slice($this->ecccode, $eccPos);
  685. $this->rsblocks[$blockNo] = array();
  686. $this->rsblocks[$blockNo]['dataLength'] = $dl;
  687. $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
  688. $this->rsblocks[$blockNo]['eccLength'] = $el;
  689. $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
  690. $this->rsblocks[$blockNo]['ecc'] = $ecc;
  691. $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
  692. $dataPos += $dl;
  693. $eccPos += $el;
  694. $blockNo++;
  695. }
  696. if ($this->rsBlockNum2($spec) == 0) {
  697. return 0;
  698. }
  699. $dl = $this->rsDataCodes2($spec);
  700. $el = $this->rsEccCodes2($spec);
  701. $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
  702. if ($rs == NULL) {
  703. return -1;
  704. }
  705. $endfor = $this->rsBlockNum2($spec);
  706. for ($i=0; $i < $endfor; ++$i) {
  707. $ecc = array_slice($this->ecccode, $eccPos);
  708. $this->rsblocks[$blockNo] = array();
  709. $this->rsblocks[$blockNo]['dataLength'] = $dl;
  710. $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
  711. $this->rsblocks[$blockNo]['eccLength'] = $el;
  712. $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
  713. $this->rsblocks[$blockNo]['ecc'] = $ecc;
  714. $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
  715. $dataPos += $dl;
  716. $eccPos += $el;
  717. $blockNo++;
  718. }
  719. return 0;
  720. }
  721. /**
  722. * Return Reed-Solomon block code.
  723. * @return array rsblocks
  724. */
  725. protected function getCode() {
  726. if ($this->count < $this->dataLength) {
  727. $row = $this->count % $this->blocks;
  728. $col = $this->count / $this->blocks;
  729. if ($col >= $this->rsblocks[0]['dataLength']) {
  730. $row += $this->b1;
  731. }
  732. $ret = $this->rsblocks[$row]['data'][$col];
  733. } elseif ($this->count < $this->dataLength + $this->eccLength) {
  734. $row = ($this->count - $this->dataLength) % $this->blocks;
  735. $col = ($this->count - $this->dataLength) / $this->blocks;
  736. $ret = $this->rsblocks[$row]['ecc'][$col];
  737. } else {
  738. return 0;
  739. }
  740. $this->count++;
  741. return $ret;
  742. }
  743. // - - - - - - - - - - - - - - - - - - - - - - - - -
  744. // QRmask
  745. /**
  746. * Write Format Information on frame and returns the number of black bits
  747. * @param $width (int) frame width
  748. * @param $frame (array) frame
  749. * @param $mask (array) masking mode
  750. * @param $level (int) error correction level
  751. * @return int blacks
  752. */
  753. protected function writeFormatInformation($width, &$frame, $mask, $level) {
  754. $blacks = 0;
  755. $format = $this->getFormatInfo($mask, $level);
  756. for ($i=0; $i<8; ++$i) {
  757. if ($format & 1) {
  758. $blacks += 2;
  759. $v = 0x85;
  760. } else {
  761. $v = 0x84;
  762. }
  763. $frame[8][$width - 1 - $i] = chr($v);
  764. if ($i < 6) {
  765. $frame[$i][8] = chr($v);
  766. } else {
  767. $frame[$i + 1][8] = chr($v);
  768. }
  769. $format = $format >> 1;
  770. }
  771. for ($i=0; $i<7; ++$i) {
  772. if ($format & 1) {
  773. $blacks += 2;
  774. $v = 0x85;
  775. } else {
  776. $v = 0x84;
  777. }
  778. $frame[$width - 7 + $i][8] = chr($v);
  779. if ($i == 0) {
  780. $frame[8][7] = chr($v);
  781. } else {
  782. $frame[8][6 - $i] = chr($v);
  783. }
  784. $format = $format >> 1;
  785. }
  786. return $blacks;
  787. }
  788. /**
  789. * mask0
  790. * @param $x (int) X position
  791. * @param $y (int) Y position
  792. * @return int mask
  793. */
  794. protected function mask0($x, $y) {
  795. return ($x + $y) & 1;
  796. }
  797. /**
  798. * mask1
  799. * @param $x (int) X position
  800. * @param $y (int) Y position
  801. * @return int mask
  802. */
  803. protected function mask1($x, $y) {
  804. return ($y & 1);
  805. }
  806. /**
  807. * mask2
  808. * @param $x (int) X position
  809. * @param $y (int) Y position
  810. * @return int mask
  811. */
  812. protected function mask2($x, $y) {
  813. return ($x % 3);
  814. }
  815. /**
  816. * mask3
  817. * @param $x (int) X position
  818. * @param $y (int) Y position
  819. * @return int mask
  820. */
  821. protected function mask3($x, $y) {
  822. return ($x + $y) % 3;
  823. }
  824. /**
  825. * mask4
  826. * @param $x (int) X position
  827. * @param $y (int) Y position
  828. * @return int mask
  829. */
  830. protected function mask4($x, $y) {
  831. return (((int)($y / 2)) + ((int)($x / 3))) & 1;
  832. }
  833. /**
  834. * mask5
  835. * @param $x (int) X position
  836. * @param $y (int) Y position
  837. * @return int mask
  838. */
  839. protected function mask5($x, $y) {
  840. return (($x * $y) & 1) + ($x * $y) % 3;
  841. }
  842. /**
  843. * mask6
  844. * @param $x (int) X position
  845. * @param $y (int) Y position
  846. * @return int mask
  847. */
  848. protected function mask6($x, $y) {
  849. return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
  850. }
  851. /**
  852. * mask7
  853. * @param $x (int) X position
  854. * @param $y (int) Y position
  855. * @return int mask
  856. */
  857. protected function mask7($x, $y) {
  858. return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
  859. }
  860. /**
  861. * Return bitmask
  862. * @param $maskNo (int) mask number
  863. * @param $width (int) width
  864. * @param $frame (array) frame
  865. * @return array bitmask
  866. */
  867. protected function generateMaskNo($maskNo, $width, $frame) {
  868. $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
  869. for ($y=0; $y<$width; ++$y) {
  870. for ($x=0; $x<$width; ++$x) {
  871. if (ord($frame[$y][$x]) & 0x80) {
  872. $bitMask[$y][$x] = 0;
  873. } else {
  874. $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
  875. $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
  876. }
  877. }
  878. }
  879. return $bitMask;
  880. }
  881. /**
  882. * makeMaskNo
  883. * @param $maskNo (int)
  884. * @param $width (int)
  885. * @param $s (int)
  886. * @param $d (int)
  887. * @param $maskGenOnly (boolean)
  888. * @return int b
  889. */
  890. protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
  891. $b = 0;
  892. $bitMask = array();
  893. $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
  894. if ($maskGenOnly) {
  895. return;
  896. }
  897. $d = $s;
  898. for ($y=0; $y<$width; ++$y) {
  899. for ($x=0; $x<$width; ++$x) {
  900. if ($bitMask[$y][$x] == 1) {
  901. $d[$y][$x] = chr(ord($s[$y][$x]) ^ ((int)($bitMask[$y][$x])));
  902. }
  903. $b += (int)(ord($d[$y][$x]) & 1);
  904. }
  905. }
  906. return $b;
  907. }
  908. /**
  909. * makeMask
  910. * @param $width (int)
  911. * @param $frame (array)
  912. * @param $maskNo (int)
  913. * @param $level (int)
  914. * @return array mask
  915. */
  916. protected function makeMask($width, $frame, $maskNo, $level) {
  917. $masked = array_fill(0, $width, str_repeat("\0", $width));
  918. $this->makeMaskNo($maskNo, $width, $frame, $masked);
  919. $this->writeFormatInformation($width, $masked, $maskNo, $level);
  920. return $masked;
  921. }
  922. /**
  923. * calcN1N3
  924. * @param $length (int)
  925. * @return int demerit
  926. */
  927. protected function calcN1N3($length) {
  928. $demerit = 0;
  929. for ($i=0; $i<$length; ++$i) {
  930. if ($this->runLength[$i] >= 5) {
  931. $demerit += (N1 + ($this->runLength[$i] - 5));
  932. }
  933. if ($i & 1) {
  934. if (($i >= 3) AND ($i < ($length-2)) AND ($this->runLength[$i] % 3 == 0)) {
  935. $fact = (int)($this->runLength[$i] / 3);
  936. if (($this->runLength[$i-2] == $fact)
  937. AND ($this->runLength[$i-1] == $fact)
  938. AND ($this->runLength[$i+1] == $fact)
  939. AND ($this->runLength[$i+2] == $fact)) {
  940. if (($this->runLength[$i-3] < 0) OR ($this->runLength[$i-3] >= (4 * $fact))) {
  941. $demerit += N3;
  942. } elseif ((($i+3) >= $length) OR ($this->runLength[$i+3] >= (4 * $fact))) {
  943. $demerit += N3;
  944. }
  945. }
  946. }
  947. }
  948. }
  949. return $demerit;
  950. }
  951. /**
  952. * evaluateSymbol
  953. * @param $width (int)
  954. * @param $frame (array)
  955. * @return int demerit
  956. */
  957. protected function evaluateSymbol($width, $frame) {
  958. $head = 0;
  959. $demerit = 0;
  960. for ($y=0; $y<$width; ++$y) {
  961. $head = 0;
  962. $this->runLength[0] = 1;
  963. $frameY = $frame[$y];
  964. if ($y > 0) {
  965. $frameYM = $frame[$y-1];
  966. }
  967. for ($x=0; $x<$width; ++$x) {
  968. if (($x > 0) AND ($y > 0)) {
  969. $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
  970. $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
  971. if (($b22 | ($w22 ^ 1)) & 1) {
  972. $demerit += N2;
  973. }
  974. }
  975. if (($x == 0) AND (ord($frameY[$x]) & 1)) {
  976. $this->runLength[0] = -1;
  977. $head = 1;
  978. $this->runLength[$head] = 1;
  979. } elseif ($x > 0) {
  980. if ((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
  981. $head++;
  982. $this->runLength[$head] = 1;
  983. } else {
  984. $this->runLength[$head]++;
  985. }
  986. }
  987. }
  988. $demerit += $this->calcN1N3($head+1);
  989. }
  990. for ($x=0; $x<$width; ++$x) {
  991. $head = 0;
  992. $this->runLength[0] = 1;
  993. for ($y=0; $y<$width; ++$y) {
  994. if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
  995. $this->runLength[0] = -1;
  996. $head = 1;
  997. $this->runLength[$head] = 1;
  998. } elseif ($y > 0) {
  999. if ((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
  1000. $head++;
  1001. $this->runLength[$head] = 1;
  1002. } else {
  1003. $this->runLength[$head]++;
  1004. }
  1005. }
  1006. }
  1007. $demerit += $this->calcN1N3($head+1);
  1008. }
  1009. return $demerit;
  1010. }
  1011. /**
  1012. * mask
  1013. * @param $width (int)
  1014. * @param $frame (array)
  1015. * @param $level (int)
  1016. * @return array best mask
  1017. */
  1018. protected function mask($width, $frame, $level) {
  1019. $minDemerit = PHP_INT_MAX;
  1020. $bestMaskNum = 0;
  1021. $bestMask = array();
  1022. $checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
  1023. if (QR_FIND_FROM_RANDOM !== false) {
  1024. $howManuOut = 8 - (QR_FIND_FROM_RANDOM % 9);
  1025. for ($i = 0; $i < $howManuOut; ++$i) {
  1026. $remPos = rand (0, count($checked_masks)-1);
  1027. unset($checked_masks[$remPos]);
  1028. $checked_masks = array_values($checked_masks);
  1029. }
  1030. }
  1031. $bestMask = $frame;
  1032. foreach ($checked_masks as $i) {
  1033. $mask = array_fill(0, $width, str_repeat("\0", $width));
  1034. $demerit = 0;
  1035. $blacks = 0;
  1036. $blacks = $this->makeMaskNo($i, $width, $frame, $mask);
  1037. $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
  1038. $blacks = (int)(100 * $blacks / ($width * $width));
  1039. $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
  1040. $demerit += $this->evaluateSymbol($width, $mask);
  1041. if ($demerit < $minDemerit) {
  1042. $minDemerit = $demerit;
  1043. $bestMask = $mask;
  1044. $bestMaskNum = $i;
  1045. }
  1046. }
  1047. return $bestMask;
  1048. }
  1049. // - - - - - - - - - - - - - - - - - - - - - - - - -
  1050. // QRsplit
  1051. /**
  1052. * Return true if the character at specified position is a number
  1053. * @param $str (string) string
  1054. * @param $pos (int) characted position
  1055. * @return boolean true of false
  1056. */
  1057. protected function isdigitat($str, $pos) {
  1058. if ($pos >= strlen($str)) {
  1059. return false;
  1060. }
  1061. return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
  1062. }
  1063. /**
  1064. * Return true if the character at specified position is an alphanumeric character
  1065. * @param $str (string) string
  1066. * @param $pos (int) characted position
  1067. * @return boolean true of false
  1068. */
  1069. protected function isalnumat($str, $pos) {
  1070. if ($pos >= strlen($str)) {
  1071. return false;
  1072. }
  1073. return ($this->lookAnTable(ord($str[$pos])) >= 0);
  1074. }
  1075. /**
  1076. * identifyMode
  1077. * @param $pos (int)
  1078. * @return int mode
  1079. */
  1080. protected function identifyMode($pos) {
  1081. if ($pos >= strlen($this->dataStr)) {
  1082. return QR_MODE_NL;
  1083. }
  1084. $c = $this->dataStr[$pos];
  1085. if ($this->isdigitat($this->dataStr, $pos)) {
  1086. return QR_MODE_NM;
  1087. } elseif ($this->isalnumat($this->dataStr, $pos)) {
  1088. return QR_MODE_AN;
  1089. } elseif ($this->hint == QR_MODE_KJ) {
  1090. if ($pos+1 < strlen($this->dataStr)) {
  1091. $d = $this->dataStr[$pos+1];
  1092. $word = (ord($c) << 8) | ord($d);
  1093. if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
  1094. return QR_MODE_KJ;
  1095. }
  1096. }
  1097. }
  1098. return QR_MODE_8B;
  1099. }
  1100. /**
  1101. * eatNum
  1102. * @return int run
  1103. */
  1104. protected function eatNum() {
  1105. $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
  1106. $p = 0;
  1107. while($this->isdigitat($this->dataStr, $p)) {
  1108. $p++;
  1109. }
  1110. $run = $p;
  1111. $mode = $this->identifyMode($p);
  1112. if ($mode == QR_MODE_8B) {
  1113. $dif = $this->estimateBitsModeNum($run) + 4 + $ln
  1114. + $this->estimateBitsMode8(1) // + 4 + l8
  1115. - $this->estimateBitsMode8($run + 1); // - 4 - l8
  1116. if ($dif > 0) {
  1117. return $this->eat8();
  1118. }
  1119. }
  1120. if ($mode == QR_MODE_AN) {
  1121. $dif = $this->estimateBitsModeNum($run) + 4 + $ln
  1122. + $this->estimateBitsModeAn(1) // + 4 + la
  1123. - $this->estimateBitsModeAn($run + 1);// - 4 - la
  1124. if ($dif > 0) {
  1125. return $this->eatAn();
  1126. }
  1127. }
  1128. $this->items = $this->appendNewInputItem($this->items, QR_MODE_NM, $run, str_split($this->dataStr));
  1129. return $run;
  1130. }
  1131. /**
  1132. * eatAn
  1133. * @return int run
  1134. */
  1135. protected function eatAn() {
  1136. $la = $this->lengthIndicator(QR_MODE_AN, $this->version);
  1137. $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
  1138. $p =1 ;
  1139. while($this->isalnumat($this->dataStr, $p)) {
  1140. if ($this->isdigitat($this->dataStr, $p)) {
  1141. $q = $p;
  1142. while($this->isdigitat($this->dataStr, $q)) {
  1143. $q++;
  1144. }
  1145. $dif = $this->estimateBitsModeAn($p) // + 4 + la
  1146. + $this->estimateBitsModeNum($q - $p) + 4 + $ln
  1147. - $this->estimateBitsModeAn($q); // - 4 - la
  1148. if ($dif < 0) {
  1149. break;
  1150. } else {
  1151. $p = $q;
  1152. }
  1153. } else {
  1154. $p++;
  1155. }
  1156. }
  1157. $run = $p;
  1158. if (!$this->isalnumat($this->dataStr, $p)) {
  1159. $dif = $this->estimateBitsModeAn($run) + 4 + $la
  1160. + $this->estimateBitsMode8(1) // + 4 + l8
  1161. - $this->estimateBitsMode8($run + 1); // - 4 - l8
  1162. if ($dif > 0) {
  1163. return $this->eat8();
  1164. }
  1165. }
  1166. $this->items = $this->appendNewInputItem($this->items, QR_MODE_AN, $run, str_split($this->dataStr));
  1167. return $run;
  1168. }
  1169. /**
  1170. * eatKanji
  1171. * @return int run
  1172. */
  1173. protected function eatKanji() {
  1174. $p = 0;
  1175. while($this->identifyMode($p) == QR_MODE_KJ) {
  1176. $p += 2;
  1177. }
  1178. $this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr));
  1179. return $run;
  1180. }
  1181. /**
  1182. * eat8
  1183. * @return int run
  1184. */
  1185. protected function eat8() {
  1186. $la = $this->lengthIndicator(QR_MODE_AN, $this->version);
  1187. $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
  1188. $p = 1;
  1189. $dataStrLen = strlen($this->dataStr);
  1190. while($p < $dataStrLen) {
  1191. $mode = $this->identifyMode($p);
  1192. if ($mode == QR_MODE_KJ) {
  1193. break;
  1194. }
  1195. if ($mode == QR_MODE_NM) {
  1196. $q = $p;
  1197. while($this->isdigitat($this->dataStr, $q)) {
  1198. $q++;
  1199. }
  1200. $dif = $this->estimateBitsMode8($p) // + 4 + l8
  1201. + $this->estimateBitsModeNum($q - $p) + 4 + $ln
  1202. - $this->estimateBitsMode8($q); // - 4 - l8
  1203. if ($dif < 0) {
  1204. break;
  1205. } else {
  1206. $p = $q;
  1207. }
  1208. } elseif ($mode == QR_MODE_AN) {
  1209. $q = $p;
  1210. while($this->isalnumat($this->dataStr, $q)) {
  1211. $q++;
  1212. }
  1213. $dif = $this->estimateBitsMode8($p) // + 4 + l8
  1214. + $this->estimateBitsModeAn($q - $p) + 4 + $la
  1215. - $this->estimateBitsMode8($q); // - 4 - l8
  1216. if ($dif < 0) {
  1217. break;
  1218. } else {
  1219. $p = $q;
  1220. }
  1221. } else {
  1222. $p++;
  1223. }
  1224. }
  1225. $run = $p;
  1226. $this->items = $this->appendNewInputItem($this->items, QR_MODE_8B, $run, str_split($this->dataStr));
  1227. return $run;
  1228. }
  1229. /**
  1230. * splitString
  1231. */
  1232. protected function splitString() {
  1233. while (strlen($this->dataStr) > 0) {
  1234. if ($this->dataStr == '') {
  1235. return 0;
  1236. }
  1237. $mode = $this->identifyMode(0);
  1238. switch ($mode) {
  1239. case QR_MODE_NM: {
  1240. $length = $this->eatNum();
  1241. break;
  1242. }
  1243. case QR_MODE_AN: {
  1244. $length = $this->eatAn();
  1245. break;
  1246. }
  1247. case QR_MODE_KJ: {
  1248. if ($hint == QR_MODE_KJ) {
  1249. $length = $this->eatKanji();
  1250. } else {
  1251. $length = $this->eat8();
  1252. }
  1253. break;
  1254. }
  1255. default: {
  1256. $length = $this->eat8();
  1257. break;
  1258. }
  1259. }
  1260. if ($length == 0) {
  1261. return 0;
  1262. }
  1263. if ($length < 0) {
  1264. return -1;
  1265. }
  1266. $this->dataStr = substr($this->dataStr, $length);
  1267. }
  1268. }
  1269. /**
  1270. * toUpper
  1271. */
  1272. protected function toUpper() {
  1273. $stringLen = strlen($this->dataStr);
  1274. $p = 0;
  1275. while ($p < $stringLen) {
  1276. $mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
  1277. if ($mode == QR_MODE_KJ) {
  1278. $p += 2;
  1279. } else {
  1280. if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
  1281. $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
  1282. }
  1283. $p++;
  1284. }
  1285. }
  1286. return $this->dataStr;
  1287. }
  1288. // - - - - - - - - - - - - - - - - - - - - - - - - -
  1289. // QRinputItem
  1290. /**
  1291. * newInputItem
  1292. * @param $mode (int)
  1293. * @param $size (int)
  1294. * @param $data (array)
  1295. * @param $bstream (array)
  1296. * @return array input item
  1297. */
  1298. protected function newInputItem($mode, $size, $data, $bstream=null) {
  1299. $setData = array_slice($data, 0, $size);
  1300. if (count($setData) < $size) {
  1301. $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
  1302. }
  1303. if (!$this->check($mode, $size, $setData)) {
  1304. return NULL;
  1305. }
  1306. $inputitem = array();
  1307. $inputitem['mode'] = $mode;
  1308. $inputitem['size'] = $size;
  1309. $inputitem['data'] = $setData;
  1310. $inputitem['bstream'] = $bstream;
  1311. return $inputitem;
  1312. }
  1313. /**
  1314. * encodeModeNum
  1315. * @param $inputitem (array)
  1316. * @param $version (int)
  1317. * @return array input item
  1318. */
  1319. protected function encodeModeNum($inputitem, $version) {
  1320. $words = (int)($inputitem['size'] / 3);
  1321. $inputitem['bstream'] = array();
  1322. $val = 0x1;
  1323. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
  1324. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_NM, $version), $inputitem['size']);
  1325. for ($i=0; $i < $words; ++$i) {
  1326. $val = (ord($inputitem['data'][$i*3 ]) - ord('0')) * 100;
  1327. $val += (ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
  1328. $val += (ord($inputitem['data'][$i*3+2]) - ord('0'));
  1329. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
  1330. }
  1331. if ($inputitem['size'] - $words * 3 == 1) {
  1332. $val = ord($inputitem['data'][$words*3]) - ord('0');
  1333. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
  1334. } elseif (($inputitem['size'] - ($words * 3)) == 2) {
  1335. $val = (ord($inputitem['data'][$words*3 ]) - ord('0')) * 10;
  1336. $val += (ord($inputitem['data'][$words*3+1]) - ord('0'));
  1337. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
  1338. }
  1339. return $inputitem;
  1340. }
  1341. /**
  1342. * encodeModeAn
  1343. * @param $inputitem (array)
  1344. * @param $version (int)
  1345. * @return array input item
  1346. */
  1347. protected function encodeModeAn($inputitem, $version) {
  1348. $words = (int)($inputitem['size'] / 2);
  1349. $inputitem['bstream'] = array();
  1350. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
  1351. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_AN, $version), $inputitem['size']);
  1352. for ($i=0; $i < $words; ++$i) {
  1353. $val = (int)($this->lookAnTable(ord($inputitem['data'][$i*2])) * 45);
  1354. $val += (int)($this->lookAnTable(ord($inputitem['data'][($i*2)+1])));
  1355. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
  1356. }
  1357. if ($inputitem['size'] & 1) {
  1358. $val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
  1359. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
  1360. }
  1361. return $inputitem;
  1362. }
  1363. /**
  1364. * encodeMode8
  1365. * @param $inputitem (array)
  1366. * @param $version (int)
  1367. * @return array input item
  1368. */
  1369. protected function encodeMode8($inputitem, $version) {
  1370. $inputitem['bstream'] = array();
  1371. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
  1372. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_8B, $version), $inputitem['size']);
  1373. for ($i=0; $i < $inputitem['size']; ++$i) {
  1374. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
  1375. }
  1376. return $inputitem;
  1377. }
  1378. /**
  1379. * encodeModeKanji
  1380. * @param $inputitem (array)
  1381. * @param $version (int)
  1382. * @return array input item
  1383. */
  1384. protected function encodeModeKanji($inputitem, $version) {
  1385. $inputitem['bstream'] = array();
  1386. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
  1387. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
  1388. for ($i=0; $i<$inputitem['size']; $i+=2) {
  1389. $val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
  1390. if ($val <= 0x9ffc) {
  1391. $val -= 0x8140;
  1392. } else {
  1393. $val -= 0xc140;
  1394. }
  1395. $h = ($val >> 8) * 0xc0;
  1396. $val = ($val & 0xff) + $h;
  1397. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
  1398. }
  1399. return $inputitem;
  1400. }
  1401. /**
  1402. * encodeModeStructure
  1403. * @param $inputitem (array)
  1404. * @return array input item
  1405. */
  1406. protected function encodeModeStructure($inputitem) {
  1407. $inputitem['bstream'] = array();
  1408. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
  1409. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
  1410. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
  1411. $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
  1412. return $inputitem;
  1413. }
  1414. /**
  1415. * encodeBitStream
  1416. * @param $inputitem (array)
  1417. * @param $version (int)
  1418. * @return array input item
  1419. */
  1420. protected function encodeBitStream($inputitem, $version) {
  1421. $inputitem['bstream'] = array();
  1422. $words = $this->maximumWords($inputitem['mode'], $version);
  1423. if ($inputitem['size'] > $words) {
  1424. $st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
  1425. $st2 = $this->newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
  1426. $st1 = $this->encodeBitStream($st1, $version);
  1427. $st2 = $this->encodeBitStream($st2, $version);
  1428. $inputitem['bstream'] = array();
  1429. $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
  1430. $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
  1431. } else {
  1432. switch($inputitem['mode']) {
  1433. case QR_MODE_NM: {
  1434. $inputitem = $this->encodeModeNum($inputitem, $version);
  1435. break;
  1436. }
  1437. case QR_MODE_AN: {
  1438. $inputitem = $this->encodeModeAn($inputitem, $version);
  1439. break;
  1440. }
  1441. case QR_MODE_8B: {
  1442. $inputitem = $this->encodeMode8($inputitem, $version);
  1443. break;
  1444. }
  1445. case QR_MODE_KJ: {
  1446. $inputitem = $this->encodeModeKanji($inputitem, $version);
  1447. break;
  1448. }
  1449. case QR_MODE_ST: {
  1450. $inputitem = $this->encodeModeStructure($inputitem);
  1451. break;
  1452. }
  1453. default: {
  1454. break;
  1455. }
  1456. }
  1457. }
  1458. return $inputitem;
  1459. }
  1460. // - - - - - - - - - - - - - - - - - - - - - - - - -
  1461. // QRinput
  1462. /**
  1463. * Append data to an input object.
  1464. * The data is copied and appended to the input object.
  1465. * @param $items (arrray) input items
  1466. * @param $mode (int) encoding mode.
  1467. * @param $size (int) size of data (byte).
  1468. * @param $data (array) array of input data.
  1469. * @return items
  1470. *
  1471. */
  1472. protected function appendNewInputItem($items, $mode, $size, $data) {
  1473. $newitem = $this->newInputItem($mode, $size, $data);
  1474. if (!empty($newitem)) {
  1475. $items[] = $newitem;
  1476. }
  1477. return $items;
  1478. }
  1479. /**
  1480. * insertStructuredAppendHeader
  1481. * @param $items (array)
  1482. * @param $size (int)
  1483. * @param $index (int)
  1484. * @param $parity (int)
  1485. * @return array items
  1486. */
  1487. protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
  1488. if ($size > MAX_STRUCTURED_SYMBOLS) {
  1489. return -1;
  1490. }
  1491. if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
  1492. return -1;
  1493. }
  1494. $buf = array($size, $index, $parity);
  1495. $entry = $this->newInputItem(QR_MODE_ST, 3, buf);
  1496. array_unshift($items, $entry);
  1497. return $items;
  1498. }
  1499. /**
  1500. * calcParity
  1501. * @param $items (array)
  1502. * @return int parity
  1503. */
  1504. protected function calcParity($items) {
  1505. $parity = 0;
  1506. foreach ($items as $item) {
  1507. if ($item['mode'] != QR_MODE_ST) {
  1508. for ($i=$item['size']-1; $i>=0; --$i) {
  1509. $parity ^= $item['data'][$i];
  1510. }
  1511. }
  1512. }
  1513. return $parity;
  1514. }
  1515. /**
  1516. * checkModeNum
  1517. * @param $size (int)
  1518. * @param $data (array)
  1519. * @return boolean true or false
  1520. */
  1521. protected function checkModeNum($size, $data) {
  1522. for ($i=0; $i<$size; ++$i) {
  1523. if ((ord($data[$i]) < ord('0')) OR (ord($data[$i]) > ord('9'))){
  1524. return false;
  1525. }
  1526. }
  1527. return true;
  1528. }
  1529. /**
  1530. * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
  1531. * @param $c (int) character value
  1532. * @return value
  1533. */
  1534. protected function lookAnTable($c) {
  1535. return (($c > 127)?-1:$this->anTable[$c]);
  1536. }
  1537. /**
  1538. * checkModeAn
  1539. * @param $size (int)
  1540. * @param $data (array)
  1541. * @return boolean true or false
  1542. */
  1543. protected function checkModeAn($size, $data) {
  1544. for ($i=0; $i<$size; ++$i) {
  1545. if ($this->lookAnTable(ord($data[$i])) == -1) {
  1546. return false;
  1547. }
  1548. }
  1549. return true;
  1550. }
  1551. /**
  1552. * estimateBitsModeNum
  1553. * @param $size (int)
  1554. * @return int number of bits
  1555. */
  1556. protected function estimateBitsModeNum($size) {
  1557. $w = (int)($size / 3);
  1558. $bits = ($w * 10);
  1559. switch($size - ($w * 3)) {
  1560. case 1: {
  1561. $bits += 4;
  1562. break;
  1563. }
  1564. case 2: {
  1565. $bits += 7;
  1566. break;
  1567. }
  1568. }
  1569. return $bits;
  1570. }
  1571. /**
  1572. * estimateBitsModeAn
  1573. * @param $size (int)
  1574. * @return int number of bits
  1575. */
  1576. protected function estimateBitsModeAn($size) {
  1577. $bits = (int)($size * 5.5); // (size / 2 ) * 11
  1578. if ($size & 1) {
  1579. $bits += 6;
  1580. }
  1581. return $bits;
  1582. }
  1583. /**
  1584. * estimateBitsMode8
  1585. * @param $size (int)
  1586. * @return int number of bits
  1587. */
  1588. protected function estimateBitsMode8($size) {
  1589. return (int)($size * 8);
  1590. }
  1591. /**
  1592. * estimateBitsModeKanji
  1593. * @param $size (int)
  1594. * @return int number of bits
  1595. */
  1596. protected function estimateBitsModeKanji($size) {
  1597. return (int)($size * 6.5); // (size / 2 ) * 13
  1598. }
  1599. /**
  1600. * checkModeKanji
  1601. * @param $size (int)
  1602. * @param $data (array)
  1603. * @return boolean true or false
  1604. */
  1605. protected function checkModeKanji($size, $data) {
  1606. if ($size & 1) {
  1607. return false;
  1608. }
  1609. for ($i=0; $i<$size; $i+=2) {
  1610. $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
  1611. if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
  1612. return false;
  1613. }
  1614. }
  1615. return true;
  1616. }
  1617. /**
  1618. * Validate the input data.
  1619. * @param $mode (int) encoding mode.
  1620. * @param $size (int) size of data (byte).
  1621. * @param $data (array) data to validate
  1622. * @return boolean true in case of valid data, false otherwise
  1623. */
  1624. protected function check($mode, $size, $data) {
  1625. if ($size <= 0) {
  1626. return false;
  1627. }
  1628. switch($mode) {
  1629. case QR_MODE_NM: {
  1630. return $this->checkModeNum($size, $data);
  1631. }
  1632. case QR_MODE_AN: {
  1633. return $this->checkModeAn($size, $data);
  1634. }
  1635. case QR_MODE_KJ: {
  1636. return $this->checkModeKanji($size, $data);
  1637. }
  1638. case QR_MODE_8B: {
  1639. return true;
  1640. }
  1641. case QR_MODE_ST: {
  1642. return true;
  1643. }
  1644. default: {
  1645. break;
  1646. }
  1647. }
  1648. return false;
  1649. }
  1650. /**
  1651. * estimateBitStreamSize
  1652. * @param $items (array)
  1653. * @param $version (int)
  1654. * @return int bits
  1655. */
  1656. protected function estimateBitStreamSize($items, $version) {
  1657. $bits = 0;
  1658. if ($version == 0) {
  1659. $version = 1;
  1660. }
  1661. foreach ($items as $item) {
  1662. switch($item['mode']) {
  1663. case QR_MODE_NM: {
  1664. $bits = $this->estimateBitsModeNum($item['size']);
  1665. break;
  1666. }
  1667. case QR_MODE_AN: {
  1668. $bits = $this->estimateBitsModeAn($item['size']);
  1669. break;
  1670. }
  1671. case QR_MODE_8B: {
  1672. $bits = $this->estimateBitsMode8($item['size']);
  1673. break;
  1674. }
  1675. case QR_MODE_KJ: {
  1676. $bits = $this->estimateBitsModeKanji($item['size']);
  1677. break;
  1678. }
  1679. case QR_MODE_ST: {
  1680. return STRUCTURE_HEADER_BITS;
  1681. }
  1682. default: {
  1683. return 0;
  1684. }
  1685. }
  1686. $l = $this->lengthIndicator($item['mode'], $version);
  1687. $m = 1 << $l;
  1688. $num = (int)(($item['size'] + $m - 1) / $m);
  1689. $bits += $num * (4 + $l);
  1690. }
  1691. return $bits;
  1692. }
  1693. /**
  1694. * estimateVersion
  1695. * @param $items (array)
  1696. * @return int version
  1697. */
  1698. protected function estimateVersion($items) {
  1699. $version = 0;
  1700. $prev = 0;
  1701. do {
  1702. $prev = $version;
  1703. $bits = $this->estimateBitStreamSize($items, $prev);
  1704. $version = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
  1705. if ($version < 0) {
  1706. re

Large files files are truncated, but you can click here to view the full file