File Source for qrcode.php

com-tecnick-tcpdf

# Source for file qrcode.php

Documentation is available at qrcode.php

1. <?php
2. //============================================================+
3. // File name : qrcode.php
4. // Version : 1.0.006
5. // Begin : 2010-03-22
6. // Last Update : 2010-08-30
7. // Author : Nicola Asuni - Tecnick.com S.r.l - Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
8. // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9. // -------------------------------------------------------------------
10. // Copyright (C) 2010-2010 Nicola Asuni - Tecnick.com S.r.l.
11. //
12. // This file is part of TCPDF software library.
13. //
14. // TCPDF is free software: you can redistribute it and/or modify it
15. // under the terms of the GNU Lesser General Public License as
16. // published by the Free Software Foundation, either version 3 of the
17. // License, or (at your option) any later version.
18. //
19. // TCPDF is distributed in the hope that it will be useful, but
20. // WITHOUT ANY WARRANTY; without even the implied warranty of
21. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22. // See the GNU Lesser General Public License for more details.
23. //
24. // You should have received a copy of the GNU Lesser General Public License
25. // along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26. //
27. // See LICENSE.TXT file for more information.
28. // -------------------------------------------------------------------
29. //
30. // DESCRIPTION :
31. //
32. // Class to create QR-code arrays for TCPDF class.
33. // QR Code symbol is a 2D barcode that can be scanned by
34. // handy terminals such as a mobile phone with CCD.
35. // The capacity of QR Code is up to 7000 digits or 4000
36. // characters, and has high robustness.
37. // This class supports QR Code model 2, described in
38. // JIS (Japanese Industrial Standards) X0510:2004
39. // or ISO/IEC 18004.
40. // Currently the following features are not supported:
41. // ECI and FNC1 mode, Micro QR Code, QR Code model 1,
42. // Structured mode.
43. //
44. // This class is derived from the following projects:
45. // ---------------------------------------------------------
46. // "PHP QR Code encoder"
47. // License: GNU-LGPLv3
48. // Copyright (C) 2010 by Dominik Dzienia <deltalab at poczta dot fm>
49. // http://phpqrcode.sourceforge.net/
50. // https://sourceforge.net/projects/phpqrcode/
51. //
52. // The "PHP QR Code encoder" is based on
53. // "C libqrencode library" (ver. 3.1.1)
54. // License: GNU-LGPL 2.1
55. // Copyright (C) 2006-2010 by Kentaro Fukuchi
56. // http://megaui.net/fukuchi/works/qrencode/index.en.html
57. //
58. // Reed-Solomon code encoder is written by Phil Karn, KA9Q.
59. // Copyright (C) 2002-2006 Phil Karn, KA9Q
60. //
61. // QR Code is registered trademark of DENSO WAVE INCORPORATED
62. // http://www.denso-wave.com/qrcode/index-e.html
63. // ---------------------------------------------------------
64. //============================================================+
66. /**
67. * Class to create QR-code arrays for TCPDF class.
68. * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
69. * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
70. * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
71. * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
72. *
73. * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
74. * Please read comments on this class source file for full copyright and license information.
75. *
76. * @package com.tecnick.tcpdf
77. * @abstract Class for generating QR-code array for TCPDF.
78. * @author Nicola Asuni
79. * @copyright 2010-2010 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
80. * @link http://www.tcpdf.org
81. * @license http://www.gnu.org/copyleft/lesser.html LGPL
82. * @version 1.0.006
83. */
85. // definitions
86. if (! defined('QRCODEDEFS')) {
88. /**
89. * Indicate that definitions for this class are set
90. */
91. define('QRCODEDEFS', true);
93. // -----------------------------------------------------
95. // Encoding modes (characters which can be encoded in QRcode)
97. /**
98. * Encoding mode
99. */
100. define('QR_MODE_NL', -1);
102. /**
103. * Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode.
104. */
105. define('QR_MODE_NM', 0);
107. /**
108. * 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.
109. */
110. define('QR_MODE_AN', 1);
112. /**
113. * Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
114. */
115. define('QR_MODE_8B', 2);
117. /**
118. * 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.
119. */
120. define('QR_MODE_KJ', 3);
122. /**
123. * Encoding mode STRUCTURED (currently unsupported)
124. */
125. define('QR_MODE_ST', 4);
127. // -----------------------------------------------------
129. // Levels of error correction.
130. // QRcode has a function of an error correcting for miss reading that white is black.
131. // Error correcting is defined in 4 level as below.
133. /**
134. * Error correction level L : About 7% or less errors can be corrected.
135. */
136. define('QR_ECLEVEL_L', 0);
138. /**
139. * Error correction level M : About 15% or less errors can be corrected.
140. */
141. define('QR_ECLEVEL_M', 1);
143. /**
144. * Error correction level Q : About 25% or less errors can be corrected.
145. */
146. define('QR_ECLEVEL_Q', 2);
148. /**
149. * Error correction level H : About 30% or less errors can be corrected.
150. */
151. define('QR_ECLEVEL_H', 3);
153. // -----------------------------------------------------
155. // Version. Size of QRcode is defined as version.
156. // Version is from 1 to 40.
157. // Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
158. // So version 40 is 177*177 matrix.
160. /**
161. * Maximum QR Code version.
162. */
163. define('QRSPEC_VERSION_MAX', 40);
165. /**
166. * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
167. */
168. define('QRSPEC_WIDTH_MAX', 177);
170. // -----------------------------------------------------
172. /**
173. * Matrix index to get width from $capacity array.
174. */
175. define('QRCAP_WIDTH', 0);
177. /**
178. * Matrix index to get number of words from $capacity array.
179. */
180. define('QRCAP_WORDS', 1);
182. /**
183. * Matrix index to get remainder from $capacity array.
184. */
185. define('QRCAP_REMINDER', 2);
187. /**
188. * Matrix index to get error correction level from $capacity array.
189. */
190. define('QRCAP_EC', 3);
192. // -----------------------------------------------------
194. // Structure (currently usupported)
196. /**
197. * Number of header bits for structured mode
198. */
199. define('STRUCTURE_HEADER_BITS', 20);
201. /**
202. * Max number of symbols for structured mode
203. */
204. define('MAX_STRUCTURED_SYMBOLS', 16);
206. // -----------------------------------------------------
208. // Masks
210. /**
211. * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
212. */
213. define('N1', 3);
215. /**
216. * Down point base value for case 2 mask pattern (module block of same color)
217. */
218. define('N2', 3);
220. /**
221. * 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)
222. */
223. define('N3', 40);
225. /**
226. * Down point base value for case 4 mask pattern (ration of dark modules in whole)
227. */
228. define('N4', 10);
230. // -----------------------------------------------------
232. // Optimization settings
234. /**
235. * if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
236. */
237. define('QR_FIND_BEST_MASK', true);
239. /**
240. * if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
241. */
242. define('QR_FIND_FROM_RANDOM', 2);
244. /**
245. * when QR_FIND_BEST_MASK === false
246. */
247. define('QR_DEFAULT_MASK', 2);
249. // -----------------------------------------------------
251. } // end of definitions
253. // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
255. if (! class_exists('QRcode', false)) {
257. // for compatibility with PHP4
258. if (! function_exists('str_split')) {
259. /**
260. * Convert a string to an array (needed for PHP4 compatibility)
261. * @param string $string The input string.
262. * @param int $split_length Maximum length of the chunk.
263. * @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.
264. */
265. function str_split($string, $split_length=1) {
266. if (( strlen($string) > $split_length) OR (!$split_length)) {
267. do {
268. $c = strlen($string);
269. $parts[] = substr($string, 0, $split_length);
270. $string = substr($string, $split_length);
271. } while ($string !== false);
272. } else {
273. $parts = array($string);
274. }
275. return $parts;
276. }
277. }
279. // #####################################################
281. /**
282. * Class to create QR-code arrays for TCPDF class.
283. * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
284. * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
285. * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
286. * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
287. *
288. * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
289. * Please read comments on this class source file for full copyright and license information.
290. *
291. * @name QRcode
292. * @package com.tecnick.tcpdf
293. * @abstract Class for generating QR-code array for TCPDF.
294. * @author Nicola Asuni
295. * @copyright 2010-2010 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
296. * @link http://www.tcpdf.org
297. * @license http://www.gnu.org/copyleft/lesser.html LGPL
298. * @version 1.0.006
299. */
300. class QRcode {
302. /**
303. * @var barcode array to be returned which is readable by TCPDF
304. * @access protected
305. */
306. protected $barcode_array = array();
308. /**
309. * @var QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix.
310. * @access protected
311. */
312. protected $version = 0;
314. /**
315. * @var Levels of error correction. See definitions for possible values.
316. * @access protected
317. */
318. protected $level = QR_ECLEVEL_L;
320. /**
321. * @var Encoding mode
322. * @access protected
323. */
324. protected $hint = QR_MODE_8B;
326. /**
327. * @var if true the input string will be converted to uppercase
328. * @access protected
329. */
330. protected $casesensitive = true;
332. /**
333. * @var structured QR code (not supported yet)
334. * @access protected
335. */
336. protected $structured = 0;
338. /**
339. * @var mask data
340. * @access protected
341. */
342. protected $data;
344. // FrameFiller
346. /**
347. * @var width
348. * @access protected
349. */
350. protected $width;
352. /**
353. * @var frame
354. * @access protected
355. */
356. protected $frame;
358. /**
359. * @var X position of bit
360. * @access protected
361. */
362. protected $x;
364. /**
365. * @var Y position of bit
366. * @access protected
367. */
368. protected $y;
370. /**
371. * @var direction
372. * @access protected
373. */
374. protected $dir;
376. /**
377. * @var single bit
378. * @access protected
379. */
380. protected $bit;
382. // ---- QRrawcode ----
384. /**
385. * @var data code
386. * @access protected
387. */
388. protected $datacode = array();
390. /**
391. * @var error correction code
392. * @access protected
393. */
394. protected $ecccode = array();
396. /**
397. * @var blocks
398. * @access protected
399. */
400. protected $blocks;
402. /**
403. * @var Reed-Solomon blocks
404. * @access protected
405. */
406. protected $rsblocks = array(); //of RSblock
408. /**
409. * @var counter
410. * @access protected
411. */
412. protected $count;
414. /**
415. * @var data length
416. * @access protected
417. */
418. protected $dataLength;
420. /**
421. * @var error correction length
422. * @access protected
423. */
424. protected $eccLength;
426. /**
427. * @var b1
428. * @access protected
429. */
430. protected $b1;
432. // ---- QRmask ----
434. /**
435. * @var run length
436. * @access protected
437. */
438. protected $runLength = array();
440. // ---- QRsplit ----
442. /**
443. * @var input data string
444. * @access protected
445. */
446. protected $dataStr = '';
448. /**
449. * @var input items
450. * @access protected
451. */
452. protected $items;
454. // Reed-Solomon items
456. /**
457. * @var Reed-Solomon items
458. * @access protected
459. */
460. protected $rsitems = array();
462. /**
463. * @var array of frames
464. * @access protected
465. */
466. protected $frames = array();
468. /**
469. * @var alphabet-numeric convesion table
470. * @access protected
471. */
472. protected $anTable = array(
473. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
474. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
475. 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
476. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, //
477. -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
478. 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
479. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
480. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 //
481. );
483. /**
484. * @var array Table of the capacity of symbols
485. * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
486. * @access protected
487. */
488. protected $capacity = array(
489. array( 0, 0, 0, array( 0, 0, 0, 0)), //
490. array( 21, 26, 0, array( 7, 10, 13, 17)), // 1
491. array( 25, 44, 7, array( 10, 16, 22, 28)), //
492. array( 29, 70, 7, array( 15, 26, 36, 44)), //
493. array( 33, 100, 7, array( 20, 36, 52, 64)), //
494. array( 37, 134, 7, array( 26, 48, 72, 88)), // 5
495. array( 41, 172, 7, array( 36, 64, 96, 112)), //
496. array( 45, 196, 0, array( 40, 72, 108, 130)), //
497. array( 49, 242, 0, array( 48, 88, 132, 156)), //
498. array( 53, 292, 0, array( 60, 110, 160, 192)), //
499. array( 57, 346, 0, array( 72, 130, 192, 224)), // 10
500. array( 61, 404, 0, array( 80, 150, 224, 264)), //
501. array( 65, 466, 0, array( 96, 176, 260, 308)), //
502. array( 69, 532, 0, array( 104, 198, 288, 352)), //
503. array( 73, 581, 3, array( 120, 216, 320, 384)), //
504. array( 77, 655, 3, array( 132, 240, 360, 432)), // 15
505. array( 81, 733, 3, array( 144, 280, 408, 480)), //
506. array( 85, 815, 3, array( 168, 308, 448, 532)), //
507. array( 89, 901, 3, array( 180, 338, 504, 588)), //
508. array( 93, 991, 3, array( 196, 364, 546, 650)), //
509. array( 97, 1085, 3, array( 224, 416, 600, 700)), // 20
510. array(101, 1156, 4, array( 224, 442, 644, 750)), //
511. array(105, 1258, 4, array( 252, 476, 690, 816)), //
512. array(109, 1364, 4, array( 270, 504, 750, 900)), //
513. array(113, 1474, 4, array( 300, 560, 810, 960)), //
514. array(117, 1588, 4, array( 312, 588, 870, 1050)), // 25
515. array(121, 1706, 4, array( 336, 644, 952, 1110)), //
516. array(125, 1828, 4, array( 360, 700, 1020, 1200)), //
517. array(129, 1921, 3, array( 390, 728, 1050, 1260)), //
518. array(133, 2051, 3, array( 420, 784, 1140, 1350)), //
519. array(137, 2185, 3, array( 450, 812, 1200, 1440)), // 30
520. array(141, 2323, 3, array( 480, 868, 1290, 1530)), //
521. array(145, 2465, 3, array( 510, 924, 1350, 1620)), //
522. array(149, 2611, 3, array( 540, 980, 1440, 1710)), //
523. array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
524. array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
525. array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
526. array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
527. array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
528. array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
529. array(177, 3706, 0, array( 750, 1372, 2040, 2430)) // 40
530. );
532. /**
533. * @var array Length indicator
534. * @access protected
535. */
536. protected $lengthTableBits = array(
537. array(10, 12, 14),
538. array( 9, 11, 13),
539. array( 8, 16, 16),
540. array( 8, 10, 12)
541. );
543. /**
544. * @var array Table of the error correction code (Reed-Solomon block)
545. * See Table 12-16 (pp.30-36), JIS X0510:2004.
546. * @access protected
547. */
548. protected $eccTable = array(
549. array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), //
550. array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1
551. array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), //
552. array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)), //
553. array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)), //
554. array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5
555. array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)), //
556. array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)), //
557. array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)), //
558. array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)), //
559. array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), // 10
560. array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)), //
561. array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)), //
562. array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)), //
563. array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)), //
564. array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), // 15
565. array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)), //
566. array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)), //
567. array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)), //
568. array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)), //
569. array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), // 20
570. array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)), //
571. array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)), //
572. array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)), //
573. array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)), //
574. array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
575. array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), //
576. array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)), //
577. array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
578. array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)), //
579. array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
580. array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)), //
581. array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), //
582. array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), //
583. array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), //
584. array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), // 35
585. array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
586. array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), //
587. array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
588. array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), //
589. array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)) // 40
590. );
592. /**
593. * @var array Positions of alignment patterns.
594. * 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.
595. * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
596. * @access protected
597. */
598. protected $alignmentPattern = array(
599. array( 0, 0),
600. array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
601. array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
602. array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
603. array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
604. array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
605. array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
606. array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
607. array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58) // 35-40
608. );
610. /**
611. * @var array Version information pattern (BCH coded).
612. * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
613. * size: [QRSPEC_VERSION_MAX - 6]
614. * @access protected
615. */
616. protected $versionPattern = array(
617. 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
618. 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
619. 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
620. 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
621. 0x27541, 0x28c69
622. );
624. /**
625. * @var array Format information
626. * @access protected
627. */
628. protected $formatInfo = array(
629. array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
630. array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
631. array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
632. array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) //
633. );
636. // -------------------------------------------------
637. // -------------------------------------------------
640. /**
641. * This is the class constructor.
642. * Creates a QRcode object
643. * @param string $code code to represent using QRcode
644. * @param string $eclevel error level: <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
645. * @access public
646. * @since 1.0.000
647. */
648. public function __construct($code, $eclevel = 'L') {
649. $barcode_array = array();
650. if (( is_null($code)) OR ($code == '\0') OR ($code == '')) {
651. return false;
652. }
653. // set error correction level
654. $this-> level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
655. if ($this-> level === false) {
656. $this-> level = QR_ECLEVEL_L;
657. }
658. if (($this-> hint != QR_MODE_8B) AND ($this-> hint != QR_MODE_KJ)) {
659. return false;
660. }
661. if (($this-> version < 0) OR ($this-> version > QRSPEC_VERSION_MAX)) {
662. return false;
663. }
664. $this-> items = array();
665. $this-> encodeString($code);
666. if ( is_null($this-> data)) {
667. return false;
668. }
669. $qrTab = $this-> binarize($this-> data);
670. $size = count($qrTab);
671. $barcode_array['num_rows'] = $size;
672. $barcode_array['num_cols'] = $size;
673. $barcode_array['bcode'] = array();
674. foreach ($qrTab as $line) {
675. $arrAdd = array();
676. foreach ( str_split($line) as $char) {
677. $arrAdd[] = ($char=='1')?1:0;
678. }
679. $barcode_array['bcode'][] = $arrAdd;
680. }
681. $this-> barcode_array = $barcode_array;
682. }
684. /**
685. * Returns a barcode array which is readable by TCPDF
686. * @return array barcode array readable by TCPDF;
687. * @access public
688. */
689. public function getBarcodeArray() {
690. return $this-> barcode_array;
691. }
693. /**
694. * Convert the frame in binary form
695. * @param array $frame array to binarize
696. * @return array frame in binary form
697. */
698. protected function binarize($frame) {
699. $len = count($frame);
700. // the frame is square (width = height)
701. foreach ($frame as &$frameLine) {
702. for ($i=0; $i<$len; $i++) {
703. $frameLine[$i] = ( ord($frameLine[$i])&1)?'1':'0';
704. }
705. }
706. return $frame;
707. }
709. /**
710. * Encode the input string to QR code
711. * @param string $string input string to encode
712. */
713. protected function encodeString($string) {
714. $this-> dataStr = $string;
715. if (!$this-> casesensitive) {
716. $this-> toUpper();
717. }
718. $ret = $this-> splitString();
719. if ($ret < 0) {
720. return NULL;
721. }
722. $this-> encodeMask(-1);
723. }
725. /**
726. * Encode mask
727. * @param int $mask masking mode
728. */
729. protected function encodeMask($mask) {
730. $spec = array(0, 0, 0, 0, 0);
731. $this-> datacode = $this-> getByteStream($this-> items);
732. if ( is_null($this-> datacode)) {
733. return NULL;
734. }
735. $spec = $this-> getEccSpec($this-> version, $this-> level, $spec);
736. $this-> b1 = $this-> rsBlockNum1($spec);
737. $this-> dataLength = $this-> rsDataLength($spec);
738. $this-> eccLength = $this-> rsEccLength($spec);
739. $this-> ecccode = array_fill(0, $this-> eccLength, 0);
740. $this-> blocks = $this-> rsBlockNum($spec);
741. $ret = $this-> init($spec);
742. if ($ret < 0) {
743. return NULL;
744. }
745. $this-> count = 0;
746. $this-> width = $this-> getWidth($this-> version);
747. $this-> frame = $this-> newFrame($this-> version);
748. $this-> x = $this-> width - 1;
749. $this-> y = $this-> width - 1;
750. $this-> dir = -1;
751. $this-> bit = -1;
752. // inteleaved data and ecc codes
753. for ($i=0; $i < ($this-> dataLength + $this-> eccLength); $i++) {
754. $code = $this-> getCode();
755. $bit = 0x80;
756. for ($j=0; $j<8; $j++) {
757. $addr = $this-> getNextPosition();
758. $this-> setFrameAt($addr, 0x02 | (($bit & $code) != 0));
759. $bit = $bit >> 1;
760. }
761. }
762. // remainder bits
763. $j = $this-> getRemainder($this-> version);
764. for ($i=0; $i<$j; $i++) {
765. $addr = $this-> getNextPosition();
766. $this-> setFrameAt($addr, 0x02);
767. }
768. // masking
769. $this-> runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
770. if ($mask < 0) {
771. if ( QR_FIND_BEST_MASK) {
772. $masked = $this-> mask($this-> width, $this-> frame, $this-> level);
773. } else {
774. $masked = $this-> makeMask($this-> width, $this-> frame, ( intval( QR_DEFAULT_MASK) % 8), $this-> level);
775. }
776. } else {
777. $masked = $this-> makeMask($this-> width, $this-> frame, $mask, $this-> level);
778. }
779. if ($masked == NULL) {
780. return NULL;
781. }
782. $this-> data = $masked;
783. }
785. // - - - - - - - - - - - - - - - - - - - - - - - - -
787. // FrameFiller
789. /**
790. * Set frame value at specified position
791. * @param array $at x,y position
792. * @param int $val value of the character to set
793. */
794. protected function setFrameAt($at, $val) {
795. $this-> frame[$at['y']][$at['x']] = chr($val);
796. }
798. /**
799. * Get frame value at specified position
800. * @param array $at x,y position
801. * @return value at specified position
802. */
803. protected function getFrameAt($at) {
804. return ord($this-> frame[$at['y']][$at['x']]);
805. }
807. /**
808. * Return the next frame position
809. * @return array of x,y coordinates
810. */
811. protected function getNextPosition() {
812. do {
813. if ($this-> bit == -1) {
814. $this-> bit = 0;
815. return array('x'=>$this-> x, 'y'=>$this-> y);
816. }
817. $x = $this-> x;
818. $y = $this-> y;
819. $w = $this-> width;
820. if ($this-> bit == 0) {
821. $x--;
822. $this-> bit++;
823. } else {
824. $x++;
825. $y += $this-> dir;
826. $this-> bit--;
827. }
828. if ($this-> dir < 0) {
829. if ($y < 0) {
830. $y = 0;
831. $x -= 2;
832. $this-> dir = 1;
833. if ($x == 6) {
834. $x--;
835. $y = 9;
836. }
837. }
838. } else {
839. if ($y == $w) {
840. $y = $w - 1;
841. $x -= 2;
842. $this-> dir = -1;
843. if ($x == 6) {
844. $x--;
845. $y -= 8;
846. }
847. }
848. }
849. if (($x < 0) OR ($y < 0)) {
850. return NULL;
851. }
852. $this-> x = $x;
853. $this-> y = $y;
854. } while( ord($this-> frame[$y][$x]) & 0x80);
855. return array('x'=>$x, 'y'=>$y);
856. }
858. // - - - - - - - - - - - - - - - - - - - - - - - - -
860. // QRrawcode
862. /**
863. * Initialize code.
864. * @param array $spec array of ECC specification
865. * @return 0 in case of success, -1 in case of error
866. */
867. protected function init($spec) {
868. $dl = $this-> rsDataCodes1($spec);
869. $el = $this-> rsEccCodes1($spec);
870. $rs = $this-> init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
871. $blockNo = 0;
872. $dataPos = 0;
873. $eccPos = 0;
874. $endfor = $this-> rsBlockNum1($spec);
875. for ($i=0; $i < $endfor; ++$i) {
876. $ecc = array_slice($this-> ecccode, $eccPos);
877. $this-> rsblocks[$blockNo] = array();
878. $this-> rsblocks[$blockNo]['dataLength'] = $dl;
879. $this-> rsblocks[$blockNo]['data'] = array_slice($this-> datacode, $dataPos);
880. $this-> rsblocks[$blockNo]['eccLength'] = $el;
881. $ecc = $this-> encode_rs_char($rs, $this-> rsblocks[$blockNo]['data'], $ecc);
882. $this-> rsblocks[$blockNo]['ecc'] = $ecc;
883. $this-> ecccode = array_merge( array_slice($this-> ecccode,0, $eccPos), $ecc);
884. $dataPos += $dl;
885. $eccPos += $el;
886. $blockNo++;
887. }
888. if ($this-> rsBlockNum2($spec) == 0) {
889. return 0;
890. }
891. $dl = $this-> rsDataCodes2($spec);
892. $el = $this-> rsEccCodes2($spec);
893. $rs = $this-> init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
894. if ($rs == NULL) {
895. return -1;
896. }
897. $endfor = $this-> rsBlockNum2($spec);
898. for ($i=0; $i < $endfor; ++$i) {
899. $ecc = array_slice($this-> ecccode, $eccPos);
900. $this-> rsblocks[$blockNo] = array();
901. $this-> rsblocks[$blockNo]['dataLength'] = $dl;
902. $this-> rsblocks[$blockNo]['data'] = array_slice($this-> datacode, $dataPos);
903. $this-> rsblocks[$blockNo]['eccLength'] = $el;
904. $ecc = $this-> encode_rs_char($rs, $this-> rsblocks[$blockNo]['data'], $ecc);
905. $this-> rsblocks[$blockNo]['ecc'] = $ecc;
906. $this-> ecccode = array_merge( array_slice($this-> ecccode, 0, $eccPos), $ecc);
907. $dataPos += $dl;
908. $eccPos += $el;
909. $blockNo++;
910. }
911. return 0;
912. }
914. /**
915. * Return Reed-Solomon block code.
916. * @return array rsblocks
917. */
918. protected function getCode() {
919. if ($this-> count < $this-> dataLength) {
920. $row = $this-> count % $this-> blocks;
921. $col = $this-> count / $this-> blocks;
922. if ($col >= $this-> rsblocks[0]['dataLength']) {
923. $row += $this-> b1;
924. }
925. $ret = $this-> rsblocks[$row]['data'][$col];
926. } elseif ($this-> count < $this-> dataLength + $this-> eccLength) {
927. $row = ($this-> count - $this-> dataLength) % $this-> blocks;
928. $col = ($this-> count - $this-> dataLength) / $this-> blocks;
929. $ret = $this-> rsblocks[$row]['ecc'][$col];
930. } else {
931. return 0;
932. }
933. $this-> count++;
934. return $ret;
935. }
937. // - - - - - - - - - - - - - - - - - - - - - - - - -
939. // QRmask
941. /**
942. * Write Format Information on frame and returns the number of black bits
943. * @param int $width frame width
944. * @param array $frame frame
945. * @param array $mask masking mode
946. * @param int $level error correction level
947. * @return int blacks
948. */
949. protected function writeFormatInformation($width, &$frame, $mask, $level) {
950. $blacks = 0;
951. $format = $this-> getFormatInfo($mask, $level);
952. for ($i=0; $i<8; ++$i) {
953. if ($format & 1) {
954. $blacks += 2;
955. $v = 0x85;
956. } else {
957. $v = 0x84;
958. }
959. $frame[8][$width - 1 - $i] = chr($v);
960. if ($i < 6) {
961. $frame[$i][8] = chr($v);
962. } else {
963. $frame[$i + 1][8] = chr($v);
964. }
965. $format = $format >> 1;
966. }
967. for ($i=0; $i<7; ++$i) {
968. if ($format & 1) {
969. $blacks += 2;
970. $v = 0x85;
971. } else {
972. $v = 0x84;
973. }
974. $frame[$width - 7 + $i][8] = chr($v);
975. if ($i == 0) {
976. $frame[8][7] = chr($v);
977. } else {
978. $frame[8][6 - $i] = chr($v);
979. }
980. $format = $format >> 1;
981. }
982. return $blacks;
983. }
985. /**
986. * mask0
987. * @param int $x X position
988. * @param int $y Y position
989. * @return int mask
990. */
991. protected function mask0($x, $y) {
992. return ($x + $y) & 1;
993. }
995. /**
996. * mask1
997. * @param int $x X position
998. * @param int $y Y position
999. * @return int mask
1000. */
1001. protected function mask1($x, $y) {
1002. return ($y & 1);
1003. }
1005. /**
1006. * mask2
1007. * @param int $x X position
1008. * @param int $y Y position
1009. * @return int mask
1010. */
1011. protected function mask2($x, $y) {
1012. return ($x % 3);
1013. }
1015. /**
1016. * mask3
1017. * @param int $x X position
1018. * @param int $y Y position
1019. * @return int mask
1020. */
1021. protected function mask3($x, $y) {
1022. return ($x + $y) % 3;
1023. }
1025. /**
1026. * mask4
1027. * @param int $x X position
1028. * @param int $y Y position
1029. * @return int mask
1030. */
1031. protected function mask4($x, $y) {
1032. return (((int)($y / 2)) + ((int)($x / 3))) & 1;
1033. }
1035. /**
1036. * mask5
1037. * @param int $x X position
1038. * @param int $y Y position
1039. * @return int mask
1040. */
1041. protected function mask5($x, $y) {
1042. return (($x * $y) & 1) + ($x * $y) % 3;
1043. }
1045. /**
1046. * mask6
1047. * @param int $x X position
1048. * @param int $y Y position
1049. * @return int mask
1050. */
1051. protected function mask6($x, $y) {
1052. return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
1053. }
1055. /**
1056. * mask7
1057. * @param int $x X position
1058. * @param int $y Y position
1059. * @return int mask
1060. */
1061. protected function mask7($x, $y) {
1062. return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
1063. }
1065. /**
1066. * Return bitmask
1067. * @param int $maskNo mask number
1068. * @param int $width width
1069. * @param array $frame frame
1070. * @return array bitmask
1071. */
1072. protected function generateMaskNo($maskNo, $width, $frame) {
1073. $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
1074. for ($y=0; $y<$width; ++$y) {
1075. for ($x=0; $x<$width; ++$x) {
1076. if ( ord($frame[$y][$x]) & 0x80) {
1077. $bitMask[$y][$x] = 0;
1078. } else {
1079. $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
1080. $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
1081. }
1082. }
1083. }
1084. return $bitMask;
1085. }
1087. /**
1088. * makeMaskNo
1089. * @param int $maskNo
1090. * @param int $width
1091. * @param int $s
1092. * @param int $d
1093. * @param boolean $maskGenOnly
1094. * @return int b
1095. */
1096. protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
1097. $b = 0;
1098. $bitMask = array();
1099. $bitMask = $this-> generateMaskNo($maskNo, $width, $s, $d);
1100. if ($maskGenOnly) {
1101. return;
1102. }
1103. $d = $s;
1104. for ($y=0; $y<$width; ++$y) {
1105. for ($x=0; $x<$width; ++$x) {
1106. if ($bitMask[$y][$x] == 1) {
1107. $d[$y][$x] = chr( ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
1108. }
1109. $b += (int)( ord($d[$y][$x]) & 1);
1110. }
1111. }
1112. return $b;
1113. }
1115. /**
1116. * makeMask
1117. * @param int $width
1118. * @param array $frame
1119. * @param int $maskNo
1120. * @param int $level
1121. * @return array mask
1122. */
1123. protected function makeMask($width, $frame, $maskNo, $level) {
1124. $masked = array_fill(0, $width, str_repeat("\0", $width));
1125. $this-> makeMaskNo($maskNo, $width, $frame, $masked);
1126. $this-> writeFormatInformation($width, $masked, $maskNo, $level);
1127. return $masked;
1128. }
1130. /**
1131. * calcN1N3
1132. * @param int $length
1133. * @return int demerit
1134. */
1135. protected function calcN1N3($length) {
1136. $demerit = 0;
1137. for ($i=0; $i<$length; ++$i) {
1138. if ($this-> runLength[$i] >= 5) {
1139. $demerit += ( N1 + ($this-> runLength[$i] - 5));
1140. }
1141. if ($i & 1) {
1142. if (($i >= 3) AND ($i < ($length-2)) AND ($this-> runLength[$i] % 3 == 0)) {
1143. $fact = (int)($this-> runLength[$i] / 3);
1144. if (($this-> runLength[$i-2] == $fact)
1145. AND ($this-> runLength[$i-1] == $fact)
1146. AND ($this-> runLength[$i+1] == $fact)
1147. AND ($this-> runLength[$i+2] == $fact)) {
1148. if (($this-> runLength[$i-3] < 0) OR ($this-> runLength[$i-3] >= (4 * $fact))) {
1149. $demerit += N3;
1150. } elseif ((($i+3) >= $length) OR ($this-> runLength[$i+3] >= (4 * $fact))) {
1151. $demerit += N3;
1152. }
1153. }
1154. }
1155. }
1156. }
1157. return $demerit;
1158. }
1160. /**
1161. * evaluateSymbol
1162. * @param int $width
1163. * @param array $frame
1164. * @return int demerit
1165. */
1166. protected function evaluateSymbol($width, $frame) {
1167. $head = 0;
1168. $demerit = 0;
1169. for ($y=0; $y<$width; ++$y) {
1170. $head = 0;
1171. $this-> runLength[0] = 1;
1172. $frameY = $frame[$y];
1173. if ($y > 0) {
1174. $frameYM = $frame[$y-1];
1175. }
1176. for ($x=0; $x<$width; ++$x) {
1177. if (($x > 0) AND ($y > 0)) {
1178. $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
1179. $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
1180. if (($b22 | ($w22 ^ 1)) & 1) {
1181. $demerit += N2;
1182. }
1183. }
1184. if (($x == 0) AND ( ord($frameY[$x]) & 1)) {
1185. $this-> runLength[0] = -1;
1186. $head = 1;
1187. $this-> runLength[$head] = 1;
1188. } elseif ($x > 0) {
1189. if (( ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
1190. $head++;
1191. $this-> runLength[$head] = 1;
1192. } else {
1193. $this-> runLength[$head]++;
1194. }
1195. }
1196. }
1197. $demerit += $this-> calcN1N3($head+1);
1198. }
1199. for ($x=0; $x<$width; ++$x) {
1200. $head = 0;
1201. $this-> runLength[0] = 1;
1202. for ($y=0; $y<$width; ++$y) {
1203. if (($y == 0) AND ( ord($frame[$y][$x]) & 1)) {
1204. $this-> runLength[0] = -1;
1205. $head = 1;
1206. $this-> runLength[$head] = 1;
1207. } elseif ($y > 0) {
1208. if (( ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
1209. $head++;
1210. $this-> runLength[$head] = 1;
1211. } else {
1212. $this-> runLength[$head]++;
1213. }
1214. }
1215. }
1216. $demerit += $this-> calcN1N3($head+1);
1217. }
1218. return $demerit;
1219. }
1221. /**
1222. * mask
1223. * @param int $width
1224. * @param array $frame
1225. * @param int $level
1226. * @return array best mask
1227. */
1228. protected function mask($width, $frame, $level) {
1229. $minDemerit = PHP_INT_MAX;
1230. $bestMaskNum = 0;
1231. $bestMask = array();
1232. $checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
1233. if ( QR_FIND_FROM_RANDOM !== false) {
1234. $howManuOut = 8 - ( QR_FIND_FROM_RANDOM % 9);
1235. for ($i = 0; $i < $howManuOut; ++$i) {
1236. $remPos = rand (0, count($checked_masks)-1);
1237. unset($checked_masks[$remPos]);
1238. $checked_masks = array_values($checked_masks);
1239. }
1240. }
1241. $bestMask = $frame;
1242. foreach ($checked_masks as $i) {
1243. $mask = array_fill(0, $width, str_repeat("\0", $width));
1244. $demerit = 0;
1245. $blacks = 0;
1246. $blacks = $this-> makeMaskNo($i, $width, $frame, $mask);
1247. $blacks += $this-> writeFormatInformation($width, $mask, $i, $level);
1248. $blacks = (int)(100 * $blacks / ($width * $width));
1249. $demerit = (int)((int)( abs($blacks - 50) / 5) * N4);
1250. $demerit += $this-> evaluateSymbol($width, $mask);
1251. if ($demerit < $minDemerit) {
1252. $minDemerit = $demerit;
1253. $bestMask = $mask;
1254. $bestMaskNum = $i;
1255. }
1256. }
1257. return $bestMask;
1258. }
1260. // - - - - - - - - - - - - - - - - - - - - - - - - -
1262. // QRsplit
1264. /**
1265. * Return true if the character at specified position is a number
1266. * @param string $str string
1267. * @param int $pos characted position
1268. * @return boolean true of false
1269. */
1270. protected function isdigitat($str, $pos) {
1271. if ($pos >= strlen($str)) {
1272. return false;
1273. }
1274. return (( ord($str[$pos]) >= ord('0'))&&( ord($str[$pos]) <= ord('9')));
1275. }
1277. /**
1278. * Return true if the character at specified position is an alphanumeric character
1279. * @param string $str string
1280. * @param int $pos characted position
1281. * @return boolean true of false
1282. */
1283. protected function isalnumat($str, $pos) {
1284. if ($pos >= strlen($str)) {
1285. return false;
1286. }
1287. return ($this-> lookAnTable( ord($str[$pos])) >= 0);
1288. }
1290. /**
1291. * identifyMode
1292. * @param int $pos
1293. * @return int mode
1294. */
1295. protected function identifyMode($pos) {
1296. if ($pos >= strlen($this-> dataStr)) {
1297. return QR_MODE_NL;
1298. }
1299. $c = $this-> dataStr[$pos];
1300. if ($this-> isdigitat($this-> dataStr, $pos)) {
1301. return QR_MODE_NM;
1302. } elseif ($this-> isalnumat($this-> dataStr, $pos)) {
1303. return QR_MODE_AN;
1304. } elseif ($this-> hint == QR_MODE_KJ) {
1305. if ($pos+1 < strlen($this-> dataStr)) {
1306. $d = $this-> dataStr[$pos+1];
1307. $word = ( ord($c) << 8) | ord($d);
1308. if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
1309. return QR_MODE_KJ;
1310. }
1311. }
1312. }
1313. return QR_MODE_8B;
1314. }
1316. /**
1317. * eatNum
1318. * @return int run
1319. */
1320. protected function eatNum() {
1321. $ln = $this-> lengthIndicator( QR_MODE_NM, $this-> version);
1322. $p = 0;
1323. while($this-> isdigitat($this-> dataStr, $p)) {
1324. $p++;
1325. }
1326. $run = $p;
1327. $mode = $this-> identifyMode($p);
1328. if ($mode == QR_MODE_8B) {
1329. $dif = $this-> estimateBitsModeNum($run) + 4 + $ln
1330. + $this-> estimateBitsMode8(1) // + 4 + l8
1331. - $this-> estimateBitsMode8($run + 1); // - 4 - l8
1332. if ($dif > 0) {
1333. return $this-> eat8();
1334. }
1335. }
1336. if ($mode == QR_MODE_AN) {
1337. $dif = $this-> estimateBitsModeNum($run) + 4 + $ln
1338. + $this-> estimateBitsModeAn(1) // + 4 + la
1339. - $this-> estimateBitsModeAn($run + 1);// - 4 - la
1340. if ($dif > 0) {
1341. return $this-> eatAn();
1342. }
1343. }
1344. $this-> items = $this-> appendNewInputItem($this-> items, QR_MODE_NM, $run, str_split($this-> dataStr));
1345. return $run;
1346. }
1348. /**
1349. * eatAn
1350. * @return int run
1351. */
1352. protected function eatAn() {
1353. $la = $this-> lengthIndicator( QR_MODE_AN, $this-> version);
1354. $ln = $this-> lengthIndicator( QR_MODE_NM, $this-> version);
1355. $p = 0;
1356. while($this-> isalnumat($this-> dataStr, $p)) {
1357. if ($this-> isdigitat($this-> dataStr, $p)) {
1358. $q = $p;
1359. while($this-> isdigitat($this-> dataStr, $q)) {
1360. $q++;
1361. }
1362. $dif = $this-> estimateBitsModeAn($p) // + 4 + la
1363. + $this-> estimateBitsModeNum($q - $p) + 4 + $ln
1364. - $this-> estimateBitsModeAn($q); // - 4 - la
1365. if ($dif < 0) {
1366. break;
1367. } else {
1368. $p = $q;
1369. }
1370. } else {
1371. $p++;
1372. }
1373. }
1374. $run = $p;
1375. if (!$this-> isalnumat($this-> dataStr, $p)) {
1376. $dif = $this-> estimateBitsModeAn($run) + 4 + $la
1377. + $this-> estimateBitsMode8(1) // + 4 + l8
1378. - $this-> estimateBitsMode8($run + 1); // - 4 - l8
1379. if ($dif > 0) {
1380. return $this-> eat8();
1381. }
1382. }
1383. $this-> items = $this-> appendNewInputItem($this-> items, QR_MODE_AN, $run, str_split($this-> dataStr));
1384. return $run;
1385. }
1387. /**
1388. * eatKanji
1389. * @return int run
1390. */
1391. protected function eatKanji() {
1392. $p = 0;
1393. while($this-> identifyMode($p) == QR_MODE_KJ) {
1394. $p += 2;
1395. }
1396. $this-> items = $this-> appendNewInputItem($this-> items, QR_MODE_KJ, $p, str_split($this-> dataStr));
1397. return $run;
1398. }
1400. /**
1401. * eat8
1402. * @return int run
1403. */
1404. protected function eat8() {
1405. $la = $this-> lengthIndicator( QR_MODE_AN, $this-> version);
1406. $ln = $this-> lengthIndicator( QR_MODE_NM, $this-> version);
1407. $p = 1;
1408. $dataStrLen = strlen($this-> dataStr);
1409. while($p < $dataStrLen) {
1410. $mode = $this-> identifyMode($p);
1411. if ($mode == QR_MODE_KJ) {
1412. break;
1413. }
1414. if ($mode == QR_MODE_NM) {
1415. $q = $p;
1416. while($this-> isdigitat($this-> dataStr, $q)) {
1417. $q++;
1418. }
1419. $dif = $this-> estimateBitsMode8($p) // + 4 + l8
1420. + $this-> estimateBitsModeNum($q - $p) + 4 + $ln
1421. - $this-> estimateBitsMode8($q); // - 4 - l8
1422. if ($dif < 0) {
1423. break;
1424. } else {
1425. $p = $q;
1426. }
1427. } elseif ($mode == QR_MODE_AN) {
1428. $q = $p;
1429. while($this-> isalnumat($this-> dataStr, $q)) {
1430. $q++;
1431. }
1432. $dif = $this-> estimateBitsMode8($p) // + 4 + l8
1433. + $this-> estimateBitsModeAn($q - $p) + 4 + $la
1434. - $this-> estimateBitsMode8($q); // - 4 - l8
1435. if ($dif < 0) {
1436. break;
1437. } else {
1438. $p = $q;
1439. }
1440. } else {
1441. $p++;
1442. }
1443. }
1444. $run = $p;
1445. $this-> items = $this-> appendNewInputItem($this-> items, QR_MODE_8B, $run, str_split($this-> dataStr));
1446. return $run;
1447. }
1449. /**
1450. * splitString
1451. */
1452. protected function splitString() {
1453. while ( strlen($this-> dataStr) > 0) {
1454. if ($this-> dataStr == '') {
1455. return 0;
1456. }
1457. $mode = $this-> identifyMode(0);
1458. switch ($mode) {
1459. case QR_MODE_NM: {
1460. $length = $this-> eatNum();
1461. break;
1462. }
1463. case QR_MODE_AN: {
1464. $length = $this-> eatAn();
1465. break;
1466. }
1467. case QR_MODE_KJ: {
1468. if ($hint == QR_MODE_KJ) {
1469. $length = $this-> eatKanji();
1470. } else {
1471. $length = $this-> eat8();
1472. }
1473. break;
1474. }
1475. default: {
1476. $length = $this-> eat8();
1477. break;
1478. }
1479. }
1480. if ($length == 0) {
1481. return 0;
1482. }
1483. if ($length < 0) {
1484. return -1;
1485. }
1486. $this-> dataStr = substr($this-> dataStr, $length);
1487. }
1488. }
1490. /**
1491. * toUpper
1492. */
1493. protected function toUpper() {
1494. $stringLen = strlen($this-> dataStr);
1495. $p = 0;
1496. while ($p < $stringLen) {
1497. $mode = $this-> identifyMode( substr($this-> dataStr, $p), $this-> hint);
1498. if ($mode == QR_MODE_KJ) {
1499. $p += 2;
1500. } else {
1501. if (( ord($this-> dataStr[$p]) >= ord('a')) AND ( ord($this-> dataStr[$p]) <= ord('z'))) {
1502. $this-> dataStr[$p] = chr( ord($this-> dataStr[$p]) - 32);
1503. }
1504. $p++;
1505. }
1506. }
1507. return $this-> dataStr;
1508. }
1510. // - - - - - - - - - - - - - - - - - - - - - - - - -
1512. // QRinputItem
1514. /**
1515. * newInputItem
1516. * @param int $mode
1517. * @param int $size
1518. * @param array $data
1519. * @param array $bstream
1520. * @return array input item
1521. */
1522. protected function newInputItem($mode, $size, $data, $bstream=null) {
1523. $setData = array_slice($data, 0, $size);
1524. if ( count($setData) < $size) {
1525. $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
1526. }
1527. if (!$this-> check($mode, $size, $setData)) {
1528. return NULL;
1529. }
1530. $inputitem = array();
1531. $inputitem['mode'] = $mode;
1532. $inputitem['size'] = $size;
1533. $inputitem['data'] = $setData;
1534. $inputitem['bstream'] = $bstream;
1535. return $inputitem;
1536. }
1538. /**
1539. * encodeModeNum
1540. * @param array $inputitem
1541. * @param int $version
1542. * @return array input item
1543. */
1544. protected function encodeModeNum($inputitem, $version) {
1545. $words = (int)($inputitem['size'] / 3);
1546. $inputitem['bstream'] = array();
1547. $val = 0x1;
1548. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, $val);
1549. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], $this-> lengthIndicator( QR_MODE_NM, $version), $inputitem['size']);
1550. for ($i=0; $i < $words; ++$i) {
1551. $val = ( ord($inputitem['data'][$i*3 ]) - ord('0')) * 100;
1552. $val += ( ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
1553. $val += ( ord($inputitem['data'][$i*3+2]) - ord('0'));
1554. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 10, $val);
1555. }
1556. if ($inputitem['size'] - $words * 3 == 1) {
1557. $val = ord($inputitem['data'][$words*3]) - ord('0');
1558. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, $val);
1559. } elseif (($inputitem['size'] - ($words * 3)) == 2) {
1560. $val = ( ord($inputitem['data'][$words*3 ]) - ord('0')) * 10;
1561. $val += ( ord($inputitem['data'][$words*3+1]) - ord('0'));
1562. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 7, $val);
1563. }
1564. return $inputitem;
1565. }
1567. /**
1568. * encodeModeAn
1569. * @param array $inputitem
1570. * @param int $version
1571. * @return array input item
1572. */
1573. protected function encodeModeAn($inputitem, $version) {
1574. $words = (int)($inputitem['size'] / 2);
1575. $inputitem['bstream'] = array();
1576. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, 0x02);
1577. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], $this-> lengthIndicator( QR_MODE_AN, $version), $inputitem['size']);
1578. for ($i=0; $i < $words; ++$i) {
1579. $val = (int)$this-> lookAnTable( ord($inputitem['data'][$i*2 ])) * 45;
1580. $val += (int)$this-> lookAnTable( ord($inputitem['data'][$i*2+1]));
1581. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 11, $val);
1582. }
1583. if ($inputitem['size'] & 1) {
1584. $val = $this-> lookAnTable( ord($inputitem['data'][($words * 2)]));
1585. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 6, $val);
1586. }
1587. return $inputitem;
1588. }
1590. /**
1591. * encodeMode8
1592. * @param array $inputitem
1593. * @param int $version
1594. * @return array input item
1595. */
1596. protected function encodeMode8($inputitem, $version) {
1597. $inputitem['bstream'] = array();
1598. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, 0x4);
1599. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], $this-> lengthIndicator( QR_MODE_8B, $version), $inputitem['size']);
1600. for ($i=0; $i < $inputitem['size']; ++$i) {
1601. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
1602. }
1603. return $inputitem;
1604. }
1606. /**
1607. * encodeModeKanji
1608. * @param array $inputitem
1609. * @param int $version
1610. * @return array input item
1611. */
1612. protected function encodeModeKanji($inputitem, $version) {
1613. $inputitem['bstream'] = array();
1614. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, 0x8);
1615. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], $this-> lengthIndicator( QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
1616. for ($i=0; $i<$inputitem['size']; $i+=2) {
1617. $val = ( ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
1618. if ($val <= 0x9ffc) {
1619. $val -= 0x8140;
1620. } else {
1621. $val -= 0xc140;
1622. }
1623. $h = ($val >> 8) * 0xc0;
1624. $val = ($val & 0xff) + $h;
1625. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 13, $val);
1626. }
1627. return $inputitem;
1628. }
1630. /**
1631. * encodeModeStructure
1632. * @param array $inputitem
1633. * @return array input item
1634. */
1635. protected function encodeModeStructure($inputitem) {
1636. $inputitem['bstream'] = array();
1637. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, 0x03);
1638. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
1639. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
1640. $inputitem['bstream'] = $this-> appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
1641. return $inputitem;
1642. }
1644. /**
1645. * encodeBitStream
1646. * @param array $inputitem
1647. * @param int $version
1648. * @return array input item
1649. */
1650. protected function encodeBitStream($inputitem, $version) {
1651. $inputitem['bstream'] = array();
1652. $words = $this-> maximumWords($inputitem['mode'], $version);
1653. if ($inputitem['size'] > $words) {
1654. $st1 = $this-> newInputItem($inputitem['mode'], $words, $inputitem['data']);
1655. $st2 = $this-> newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
1656. $st1 = $this-> encodeBitStream($st1, $version);
1657. $st2 = $this-> encodeBitStream($st2, $version);
1658. $inputitem['bstream'] = array();
1659. $inputitem['bstream'] = $this-> appendBitstream($inputitem['bstream'], $st1['bstream']);
1660. $inputitem['bstream'] = $this-> appendBitstream($inputitem['bstream'], $st2['bstream']);
1661. } else {
1662. switch($inputitem['mode']) {
1663. case QR_MODE_NM: {
1664. $inputitem = $this-> encodeModeNum($inputitem, $version);
1665. break;
1666. }
1667. case QR_MODE_AN: {
1668. $inputitem = $this-> encodeModeAn($inputitem, $version);
1669. break;
1670. }
1671. case QR_MODE_8B: {
1672. $inputitem = $this-> encodeMode8($inputitem, $version);
1673. break;
1674. }
1675. case QR_MODE_KJ: {
1676. $inputitem = $this-> encodeModeKanji($inputitem, $version);
1677. break;
1678. }
1679. case QR_MODE_ST: {
1680. $inputitem = $this-> encodeModeStructure($inputitem);
1681. break;
1682. }
1683. default: {
1684. break;
1685. }
1686. }
1687. }
1688. return $inputitem;
1689. }
1691. // - - - - - - - - - - - - - - - - - - - - - - - - -
1693. // QRinput
1695. /**
1696. * Append data to an input object.
1697. * The data is copied and appended to the input object.
1698. * @param array items input items
1699. * @param int $mode encoding mode.
1700. * @param int $size size of data (byte).
1701. * @param array $data array of input data.
1702. * @return items
1703. *
1704. */
1705. protected function appendNewInputItem($items, $mode, $size, $data) {
1706. $items[] = $this-> newInputItem($mode, $size, $data);
1707. return $items;
1708. }
1710. /**
1711. * insertStructuredAppendHeader
1712. * @param array $items
1713. * @param int $size
1714. * @param int $index
1715. * @param int $parity
1716. * @return array items
1717. */
1718. protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
1719. if ($size > MAX_STRUCTURED_SYMBOLS) {
1720. return -1;
1721. }
1722. if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
1723. return -1;
1724. }
1725. $buf = array($size, $index, $parity);
1726. $entry = $this-> newInputItem( QR_MODE_ST, 3, buf);
1727. array_unshift($items, $entry);
1728. return $items;
1729. }
1731. /**
1732. * calcParity
1733. * @param array $items
1734. * @return int parity
1735. */
1736. protected function calcParity($items) {
1737. $parity = 0;
1738. foreach ($items as $item) {
1739. if ($item['mode'] != QR_MODE_ST) {
1740. for ($i=$item['size']-1; $i>=0; --$i) {
1741. $parity ^= $item['data'][$i];
1742. }
1743. }
1744. }
1745. return $parity;
1746. }
1748. /**
1749. * checkModeNum
1750. * @param int $size
1751. * @param array $data
1752. * @return boolean true or false
1753. */
1754. protected function checkModeNum($size, $data) {
1755. for ($i=0; $i<$size; ++$i) {
1756. if (( ord($data[$i]) < ord('0')) OR ( ord($data[$i]) > ord('9'))){
1757. return false;
1758. }
1759. }
1760. return true;
1761. }
1763. /**
1764. * estimateBitsModeNum
1765. * @param int $size
1766. * @return int number of bits
1767. */
1768. protected function estimateBitsModeNum($size) {
1769. $w = (int)$size / 3;
1770. $bits = $w * 10;
1771. switch($size - $w * 3) {
1772. case 1: {
1773. $bits += 4;
1774. break;
1775. }
1776. case 2: {
1777. $bits += 7;
1778. break;
1779. }
1780. default: {
1781. break;
1782. }
1783. }
1784. return $bits;
1785. }
1787. /**
1788. * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
1789. * @param int $c character value
1790. * @return value
1791. */
1792. protected function lookAnTable($c) {
1793. return (($c > 127)?-1:$this-> anTable[$c]);
1794. }
1796. /**
1797. * checkModeAn
1798. * @param int $size
1799. * @param array $data
1800. * @return boolean true or false
1801. */
1802. protected function checkModeAn($size, $data) {
1803. for ($i=0; $i<$size; ++$i) {
1804. if ($this-> lookAnTable( ord($data[$i])) == -1) {
1805. return false;
1806. }
1807. }
1808. return true;
1809. }
1811. /**
1812. * estimateBitsModeAn
1813. * @param int $size
1814. * @return int number of bits
1815. */
1816. protected function estimateBitsModeAn($size) {
1817. $w = (int)($size / 2);
1818. $bits = $w * 11;
1819. if ($size & 1) {
1820. $bits += 6;
1821. }
1822. return $bits;
1823. }
1825. /**
1826. * estimateBitsMode8
1827. * @param int $size
1828. * @return int number of bits
1829. */
1830. protected function estimateBitsMode8($size) {
1831. return $size * 8;
1832. }
1834. /**
1835. * estimateBitsModeKanji
1836. * @param int $size
1837. * @return int number of bits
1838. */
1839. protected function estimateBitsModeKanji($size) {
1840. return (int)(($size / 2) * 13);
1841. }
1843. /**
1844. * checkModeKanji
1845. * @param int $size
1846. * @param array $data
1847. * @return boolean true or false
1848. */
1849. protected function checkModeKanji($size, $data) {
1850. if ($size & 1) {
1851. return false;
1852. }
1853. for ($i=0; $i<$size; $i+=2) {
1854. $val = ( ord($data[$i]) << 8) | ord($data[$i+1]);
1855. if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
1856. return false;
1857. }
1858. }
1859. return true;
1860. }
1862. /**
1863. * Validate the input data.
1864. * @param int $mode encoding mode.
1865. * @param int $size size of data (byte).
1866. * @param array data data to validate
1867. * @return boolean true in case of valid data, false otherwise
1868. */
1869. protected function check($mode, $size, $data) {
1870. if ($size <= 0) {
1871. return false;
1872. }
1873. switch($mode) {
1874. case QR_MODE_NM: {
1875. return $this-> checkModeNum($size, $data);
1876. }
1877. case QR_MODE_AN: {
1878. return $this-> checkModeAn($size, $data);
1879. }
1880. case QR_MODE_KJ: {
1881. return $this-> checkModeKanji($size, $data);
1882. }
1883. case QR_MODE_8B: {
1884. return true;
1885. }
1886. case QR_MODE_ST: {
1887. return true;
1888. }
1889. default: {
1890. break;
1891. }
1892. }
1893. return false;
1894. }
1896. /**
1897. * estimateBitStreamSize
1898. * @param array $items
1899. * @param int $version
1900. * @return int bits
1901. */
1902. protected function estimateBitStreamSize($items, $version) {
1903. $bits = 0;
1904. if ($version == 0) {
1905. $version = 1;
1906. }
1907. foreach ($items as $item) {
1908. switch($item['mode']) {
1909. case QR_MODE_NM: {
1910. $bits = $this-> estimateBitsModeNum($item['size']);
1911. break;
1912. }
1913. case QR_MODE_AN: {
1914. $bits = $this-> estimateBitsModeAn($item['size']);
1915. break;
1916. }
1917. case QR_MODE_8B: {
1918. $bits = $this-> estimateBitsMode8($item['size']);
1919. break;
1920. }
1921. case QR_MODE_KJ: {
1922. $bits = $this-> estimateBitsModeKanji($item['size']);
1923. break;
1924. }
1925. case QR_MODE_ST: {
1926. return STRUCTURE_HEADER_BITS;
1927. }
1928. default: {
1929. return 0;
1930. }
1931. }
1932. $l = $this-> lengthIndicator($item['mode'], $version);
1933. $m = 1 << $l;
1934. $num = (int)(($item['size'] + $m - 1) / $m);
1935. $bits += $num * (4 + $l);
1936. }
1937. return $bits;
1938. }
1940. /**
1941. * estimateVersion
1942. * @param array $items
1943. * @return int version
1944. */
1945. protected function estimateVersion($items) {
1946. $version = 0;
1947. $prev = 0;
1948. do {
1949. $prev = $version;
1950. $bits = $this-> estimateBitStreamSize($items, $prev);
1951. $version = $this-> getMinimumVersion((int)(($bits + 7) / 8), $this-> level);
1952. if ($version < 0) {
1953. return -1;
1954. }
1955. } while ($version > $prev);
1956. return $version;
1957. }
1959. /**
1960. * lengthOfCode
1961. * @param int $mode
1962. * @param int $version
1963. * @param int $bits
1964. * @return int size
1965. */
1966. protected function lengthOfCode($mode, $version, $bits) {
1967. $payload = $bits - 4 - $this-> lengthIndicator($mode, $version);
1968. switch($mode) {
1969. case QR_MODE_NM: {
1970. $chunks = (int)($payload / 10);
1971. $remain = $payload - $chunks * 10;
1972. $size = $chunks * 3;
1973. if ($remain >= 7) {
1974. $size += 2;
1975. } elseif ($remain >= 4) {
1976. $size += 1;
1977. }
1978. break;
1979. }
1980. case QR_MODE_AN: {
1981. $chunks = (int)($payload / 11);
1982. $remain = $payload - $chunks * 11;
1983. $size = $chunks * 2;
1984. if ($remain >= 6) {
1985. ++$size;
1986. }
1987. break;
1988. }
1989. case QR_MODE_8B: {
1990. $size = (int)($payload / 8);
1991. break;
1992. }
1993. case QR_MODE_KJ: {
1994. $size = (int)(($payload / 13) * 2);
1995. break;
1996. }
1997. case QR_MODE_ST: {
1998. $size = (int)($payload / 8);
1999. break;
2000. }
2001. default: {
2002. $size = 0;
2003. break;
2004. }
2005. }
2006. $maxsize = $this-> maximumWords($mode, $version);
2007. if ($size < 0) {
2008. $size = 0;
2009. }
2010. if ($size > $maxsize) {
2011. $size = $maxsize;
2012. }
2013. return $size;
2014. }
2016. /**
2017. * createBitStream
2018. * @param array $items
2019. * @return array of items and total bits
2020. */
2021. protected function createBitStream($items) {
2022. $total = 0;
2023. foreach ($items as $key => $item) {
2024. $items[$key] = $this-> encodeBitStream($item, $this-> version);
2025. $bits = count($items[$key]['bstream']);
2026. $total += $bits;
2027. }
2028. return array($items, $total);
2029. }
2031. /**
2032. * convertData
2033. * @param array $items
2034. * @return array items
2035. */
2036. protected function convertData($items) {
2037. $ver = $this-> estimateVersion($items);
2038. if ($ver > $this-> version) {
2039. $this-> version = $ver;
2040. }
2041. for (;;) {
2042. $cbs = $this-> createBitStream($items);
2043. $items = $cbs[0];
2044. $bits = $cbs[1];
2045. if ($bits < 0) {
2046. return -1;
2047. }
2048. $ver = $this-> getMinimumVersion((int)(($bits + 7) / 8), $this-> level);
2049. if ($ver < 0) {
2050. return -1;
2051. } elseif ($ver > $this-> version) {
2052. $this-> version = $ver;
2053. } else {
2054. break;
2055. }
2056. }
2057. return $items;
2058. }
2060. /**
2061. * Append Padding Bit to bitstream
2062. * @param array $bstream
2063. * @return array bitstream
2064. */
2065. protected function appendPaddingBit($bstream) {
2066. if ( is_null($bstream)) {
2067. return null;
2068. }
2069. $bits = count($bstream);
2070. $maxwords = $this-> getDataLength($this-> version, $this-> level);
2071. $maxbits = $maxwords * 8;
2072. if ($maxbits == $bits) {
2073. return 0;
2074. }
2075. if ($maxbits - $bits < 5) {
2076. return $this-> appendNum($bstream, $maxbits - $bits, 0);
2077. }
2078. $bits += 4;
2079. $words = (int)(($bits + 7) / 8);
2080. $padding = array();
2081. $padding = $this-> appendNum($padding, $words * 8 - $bits + 4, 0);
2082. $padlen = $maxwords - $words;
2083. if ($padlen > 0) {
2084. $padbuf = array();
2085. for ($i=0; $i<$padlen; ++$i) {
2086. $padbuf[$i] = ($i&1)?0x11:0xec;
2087. }
2088. $padding = $this-> appendBytes($padding, $padlen, $padbuf);
2089. }
2090. return $this-> appendBitstream($bstream, $padding);
2091. }
2093. /**
2094. * mergeBitStream
2095. * @param array $bstream
2096. * @return array bitstream
2097. */
2098. protected function mergeBitStream($items) {
2099. $items = $this-> convertData($items);
2100. if (! is_array($items)) {
2101. return null;
2102. }
2103. $bstream = array();
2104. foreach ($items as $item) {
2105. $bstream = $this-> appendBitstream($bstream, $item['bstream']);
2106. }
2107. return $bstream;
2108. }
2110. /**
2111. * Returns a stream of bits.
2112. * @param int $items
2113. * @return array padded merged byte stream
2114. */
2115. protected function getBitStream($items) {
2116. $bstream = $this-> mergeBitStream($items);
2117. return $this-> appendPaddingBit($bstream);
2118. }
2120. /**
2121. * Pack all bit streams padding bits into a byte array.
2122. * @param int $items
2123. * @return array padded merged byte stream
2124. */
2125. protected function getByteStream($items) {
2126. $bstream = $this-> getBitStream($items);
2127. return $this-> bitstreamToByte($bstream);
2128. }
2130. // - - - - - - - - - - - - - - - - - - - - - - - - -
2132. // QRbitstream
2134. /**
2135. * Return an array with zeros
2136. * @param int $setLength array size
2137. * @return array
2138. */
2139. protected function allocate($setLength) {
2140. return array_fill(0, $setLength, 0);
2141. }
2143. /**
2144. * Return new bitstream from number
2145. * @param int $bits number of bits
2146. * @param int $num number
2147. * @return array bitstream
2148. */
2149. protected function newFromNum($bits, $num) {
2150. $bstream = $this-> allocate($bits);
2151. $mask = 1 << ($bits - 1);
2152. for ($i=0; $i<$bits; ++$i) {
2153. if ($num & $mask) {
2154. $bstream[$i] = 1;
2155. } else {
2156. $bstream[$i] = 0;
2157. }
2158. $mask = $mask >> 1;
2159. }
2160. return $bstream;
2161. }
2163. /**
2164. * Return new bitstream from bytes
2165. * @param int $size size
2166. * @param array $data bytes
2167. * @return array bitstream
2168. */
2169. protected function newFromBytes($size, $data) {
2170. $bstream = $this-> allocate($size * 8);
2171. $p=0;
2172. for ($i=0; $i<$size; ++$i) {
2173. $mask = 0x80;
2174. for ($j=0; $j<8; ++$j) {
2175. if ($data[$i] & $mask) {
2176. $bstream[$p] = 1;
2177. } else {
2178. $bstream[$p] = 0;
2179. }
2180. $p++;
2181. $mask = $mask >> 1;
2182. }
2183. }
2184. return $bstream;
2185. }
2187. /**
2188. * Append one bitstream to another
2189. * @param array $bitstream original bitstream
2190. * @param array $append bitstream to append
2191. * @return array bitstream
2192. */
2193. protected function appendBitstream($bitstream, $append) {
2194. if ((! is_array($append)) OR ( count($append) == 0)) {
2195. return $bitstream;
2196. }
2197. if ( count($bitstream) == 0) {
2198. return $append;
2199. }
2200. return array_values( array_merge($bitstream, $append));
2201. }
2203. /**
2204. * Append one bitstream created from number to another
2205. * @param array $bitstream original bitstream
2206. * @param int $bits number of bits
2207. * @param int $num number
2208. * @return array bitstream
2209. */
2210. protected function appendNum($bitstream, $bits, $num) {
2211. if ($bits == 0) {
2212. return 0;
2213. }
2214. $b = $this-> newFromNum($bits, $num);
2215. return $this-> appendBitstream($bitstream, $b);
2216. }
2218. /**
2219. * Append one bitstream created from bytes to another
2220. * @param array $bitstream original bitstream
2221. * @param int $size size
2222. * @param array $data bytes
2223. * @return array bitstream
2224. */
2225. protected function appendBytes($bitstream, $size, $data) {
2226. if ($size == 0) {
2227. return 0;
2228. }
2229. $b = $this-> newFromBytes($size, $data);
2230. return $this-> appendBitstream($bitstream, $b);
2231. }
2233. /**
2234. * Convert bitstream to bytes
2235. * @param array $bitstream original bitstream
2236. * @return array of bytes
2237. */
2238. protected function bitstreamToByte($bstream) {
2239. if ( is_null($bstream)) {
2240. return null;
2241. }
2242. $size = count($bstream);
2243. if ($size == 0) {
2244. return array();
2245. }
2246. $data = array_fill(0, (int)(($size + 7) / 8), 0);
2247. $bytes = (int)($size / 8);
2248. $p = 0;
2249. for ($i=0; $i<$bytes; $i++) {
2250. $v = 0;
2251. for ($j=0; $j<8; $j++) {
2252. $v = $v << 1;
2253. $v |= $bstream[$p];
2254. $p++;
2255. }
2256. $data[$i] = $v;
2257. }
2258. if ($size & 7) {
2259. $v = 0;
2260. for ($j=0; $j<($size & 7); $j++) {
2261. $v = $v << 1;
2262. $v |= $bstream[$p];
2263. $p++;
2264. }
2265. $data[$bytes] = $v;
2266. }
2267. return $data;
2268. }
2270. // - - - - - - - - - - - - - - - - - - - - - - - - -
2272. // QRspec
2274. /**
2275. * Replace a value on the array at the specified position
2276. * @param array $srctab
2277. * @param int $x X position
2278. * @param int $y Y position
2279. * @param string $repl value to replace
2280. * @param int $replLen length of the repl string
2281. * @return array srctab
2282. */
2283. protected function qrstrset($srctab, $x, $y, $repl, $replLen=false) {
2284. $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
2285. return $srctab;
2286. }
2288. /**
2289. * Return maximum data code length (bytes) for the version.
2290. * @param int $version version
2291. * @param int $level error correction level
2292. * @return int maximum size (bytes)
2293. */
2294. protected function getDataLength($version, $level) {
2295. return $this-> capacity[$version][ QRCAP_WORDS] - $this-> capacity[$version][ QRCAP_EC][$level];
2296. }
2298. /**
2299. * Return maximum error correction code length (bytes) for the version.
2300. * @param int $version version
2301. * @param int $level error correction level
2302. * @return int ECC size (bytes)
2303. */
2304. protected function getECCLength($version, $level){
2305. return $this-> capacity[$version][ QRCAP_EC][$level];
2306. }
2308. /**
2309. * Return the width of the symbol for the version.
2310. * @param int $version version
2311. * @return int width
2312. */
2313. protected function getWidth($version) {
2314. return $this-> capacity[$version][ QRCAP_WIDTH];
2315. }
2317. /**
2318. * Return the numer of remainder bits.
2319. * @param int $version version
2320. * @return int number of remainder bits
2321. */
2322. protected function getRemainder($version) {
2323. return $this-> capacity[$version][ QRCAP_REMINDER];
2324. }
2326. /**
2327. * Return a version number that satisfies the input code length.
2328. * @param int $size input code length (byte)
2329. * @param int $level error correction level
2330. * @return int version number
2331. */
2332. protected function getMinimumVersion($size, $level) {
2333. for ($i=1; $i <= QRSPEC_VERSION_MAX; ++$i) {
2334. $words = $this-> capacity[$i][ QRCAP_WORDS] - $this-> capacity[$i][ QRCAP_EC][$level];
2335. if ($words >= $size) {
2336. return $i;
2337. }
2338. }
2339. return -1;
2340. }
2342. /**
2343. * Return the size of length indicator for the mode and version.
2344. * @param int $mode encoding mode
2345. * @param int $version version
2346. * @return int the size of the appropriate length indicator (bits).
2347. */
2348. protected function lengthIndicator($mode, $version) {
2349. if ($mode == QR_MODE_ST) {
2350. return 0;
2351. }
2352. if ($version <= 9) {
2353. $l = 0;
2354. } elseif ($version <= 26) {
2355. $l = 1;
2356. } else {
2357. $l = 2;
2358. }
2359. return $this-> lengthTableBits[$mode][$l];
2360. }
2362. /**
2363. * Return the maximum length for the mode and version.
2364. * @param int $mode encoding mode
2365. * @param int $version version
2366. * @return int the maximum length (bytes)
2367. */
2368. protected function maximumWords($mode, $version) {
2369. if ($mode == QR_MODE_ST) {
2370. return 3;
2371. }
2372. if ($version <= 9) {
2373. $l = 0;
2374. } else if ($version <= 26) {
2375. $l = 1;
2376. } else {
2377. $l = 2;
2378. }
2379. $bits = $this-> lengthTableBits[$mode][$l];
2380. $words = (1 << $bits) - 1;
2381. if ($mode == QR_MODE_KJ) {
2382. $words *= 2; // the number of bytes is required
2383. }
2384. return $words;
2385. }
2387. /**
2388. * Return an array of ECC specification.
2389. * @param int $version version
2390. * @param int $level error correction level
2391. * @param array $spec an array of ECC specification contains as following: {# of type1 blocks, # of data code, # of ecc code, # of type2 blocks, # of data code}
2392. * @return array spec
2393. */
2394. protected function getEccSpec($version, $level, $spec) {
2395. if ( count($spec) < 5) {
2396. $spec = array(0, 0, 0, 0, 0);
2397. }
2398. $b1 = $this-> eccTable[$version][$level][0];
2399. $b2 = $this-> eccTable[$version][$level][1];
2400. $data = $this-> getDataLength($version, $level);
2401. $ecc = $this-> getECCLength($version, $level);
2402. if ($b2 == 0) {
2403. $spec[0] = $b1;
2404. $spec[1] = (int)($data / $b1);
2405. $spec[2] = (int)($ecc / $b1);
2406. $spec[3] = 0;
2407. $spec[4] = 0;
2408. } else {
2409. $spec[0] = $b1;
2410. $spec[1] = (int)($data / ($b1 + $b2));
2411. $spec[2] = (int)($ecc / ($b1 + $b2));
2412. $spec[3] = $b2;
2413. $spec[4] = $spec[1] + 1;
2414. }
2415. return $spec;
2416. }
2418. /**
2419. * Put an alignment marker.
2420. * @param array $frame frame
2421. * @param int $width width
2422. * @param int $ox X center coordinate of the pattern
2423. * @param int $oy Y center coordinate of the pattern
2424. * @return array frame
2425. */
2426. protected function putAlignmentMarker($frame, $ox, $oy) {
2427. $finder = array(
2428. "\xa1\xa1\xa1\xa1\xa1",
2429. "\xa1\xa0\xa0\xa0\xa1",
2430. "\xa1\xa0\xa1\xa0\xa1",
2431. "\xa1\xa0\xa0\xa0\xa1",
2432. "\xa1\xa1\xa1\xa1\xa1"
2433. );
2434. $yStart = $oy - 2;
2435. $xStart = $ox - 2;
2436. for ($y=0; $y < 5; $y++) {
2437. $frame = $this-> qrstrset($frame, $xStart, $yStart+$y, $finder[$y]);
2438. }
2439. return $frame;
2440. }
2442. /**
2443. * Put an alignment pattern.
2444. * @param int $version version
2445. * @param array $fram frame
2446. * @param int $width width
2447. * @return array frame
2448. */
2449. protected function putAlignmentPattern($version, $frame, $width) {
2450. if ($version < 2) {
2451. return $frame;
2452. }
2453. $d = $this-> alignmentPattern[$version][1] - $this-> alignmentPattern[$version][0];
2454. if ($d < 0) {
2455. $w = 2;
2456. } else {
2457. $w = (int)(($width - $this-> alignmentPattern[$version][0]) / $d + 2);
2458. }
2459. if ($w * $w - 3 == 1) {
2460. $x = $this-> alignmentPattern[$version][0];
2461. $y = $this-> alignmentPattern[$version][0];
2462. $frame = $this-> putAlignmentMarker($frame, $x, $y);
2463. return $frame;
2464. }
2465. $cx = $this-> alignmentPattern[$version][0];
2466. $wo = $w - 1;
2467. for ($x=1; $x < $wo; ++$x) {
2468. $frame = $this-> putAlignmentMarker($frame, 6, $cx);
2469. $frame = $this-> putAlignmentMarker($frame, $cx, 6);
2470. $cx += $d;
2471. }
2472. $cy = $this-> alignmentPattern[$version][0];
2473. for ($y=0; $y < $wo; ++$y) {
2474. $cx = $this-> alignmentPattern[$version][0];
2475. for ($x=0; $x < $wo; ++$x) {
2476. $frame = $this-> putAlignmentMarker($frame, $cx, $cy);
2477. $cx += $d;
2478. }
2479. $cy += $d;
2480. }
2481. return $frame;
2482. }
2484. /**
2485. * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits.
2486. * @param int $version version
2487. * @return BCH encoded version information pattern
2488. */
2489. protected function getVersionPattern($version) {
2490. if (($version < 7) OR ($version > QRSPEC_VERSION_MAX)) {
2491. return 0;
2492. }
2493. return $this-> versionPattern[($version - 7)];
2494. }
2496. /**
2497. * Return BCH encoded format information pattern.
2498. * @param array $mask
2499. * @param int $level error correction level
2500. * @return BCH encoded format information pattern
2501. */
2502. protected function getFormatInfo($mask, $level) {
2503. if (($mask < 0) OR ($mask > 7)) {
2504. return 0;
2505. }
2506. if (($level < 0) OR ($level > 3)) {
2507. return 0;
2508. }
2509. return $this-> formatInfo[$level][$mask];
2510. }
2512. /**
2513. * Put a finder pattern.
2514. * @param array $frame frame
2515. * @param int $width width
2516. * @param int $ox X center coordinate of the pattern
2517. * @param int $oy Y center coordinate of the pattern
2518. * @return array frame
2519. */
2520. protected function putFinderPattern($frame, $ox, $oy) {
2521. $finder = array(
2522. "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
2523. "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2524. "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2525. "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2526. "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2527. "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2528. "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
2529. );
2530. for ($y=0; $y < 7; $y++) {
2531. $frame = $this-> qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
2532. }
2533. return $frame;
2534. }
2536. /**
2537. * Return a copy of initialized frame.
2538. * @param int $version version
2539. * @return Array of unsigned char.
2540. */
2541. protected function createFrame($version) {
2542. $width = $this-> capacity[$version][ QRCAP_WIDTH];
2543. $frameLine = str_repeat ("\0", $width);
2544. $frame = array_fill(0, $width, $frameLine);
2545. // Finder pattern
2546. $frame = $this-> putFinderPattern($frame, 0, 0);
2547. $frame = $this-> putFinderPattern($frame, $width - 7, 0);
2548. $frame = $this-> putFinderPattern($frame, 0, $width - 7);
2549. // Separator
2550. $yOffset = $width - 7;
2551. for ($y=0; $y < 7; ++$y) {
2552. $frame[$y][7] = "\xc0";
2553. $frame[$y][$width - 8] = "\xc0";
2554. $frame[$yOffset][7] = "\xc0";
2555. ++$yOffset;
2556. }
2557. $setPattern = str_repeat("\xc0", 8);
2558. $frame = $this-> qrstrset($frame, 0, 7, $setPattern);
2559. $frame = $this-> qrstrset($frame, $width-8, 7, $setPattern);
2560. $frame = $this-> qrstrset($frame, 0, $width - 8, $setPattern);
2561. // Format info
2562. $setPattern = str_repeat("\x84", 9);
2563. $frame = $this-> qrstrset($frame, 0, 8, $setPattern);
2564. $frame = $this-> qrstrset($frame, $width - 8, 8, $setPattern, 8);
2565. $yOffset = $width - 8;
2566. for ($y=0; $y < 8; ++$y,++$yOffset) {
2567. $frame[$y][8] = "\x84";
2568. $frame[$yOffset][8] = "\x84";
2569. }
2570. // Timing pattern
2571. $wo = $width - 15;
2572. for ($i=1; $i < $wo; ++$i) {
2573. $frame[6][7+$i] = chr(0x90 | ($i & 1));
2574. $frame[7+$i][6] = chr(0x90 | ($i & 1));
2575. }
2576. // Alignment pattern
2577. $frame = $this-> putAlignmentPattern($version, $frame, $width);
2578. // Version information
2579. if ($version >= 7) {
2580. $vinf = $this-> getVersionPattern($version);
2581. $v = $vinf;
2582. for ($x=0; $x<6; ++$x) {
2583. for ($y=0; $y<3; ++$y) {
2584. $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
2585. $v = $v >> 1;
2586. }
2587. }
2588. $v = $vinf;
2589. for ($y=0; $y<6; ++$y) {
2590. for ($x=0; $x<3; ++$x) {
2591. $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
2592. $v = $v >> 1;
2593. }
2594. }
2595. }
2596. // and a little bit...
2597. $frame[$width - 8][8] = "\x81";
2598. return $frame;
2599. }
2601. /**
2602. * Set new frame for the specified version.
2603. * @param int $version version
2604. * @return Array of unsigned char.
2605. */
2606. protected function newFrame($version) {
2607. if (($version < 1) OR ($version > QRSPEC_VERSION_MAX)) {
2608. return NULL;
2609. }
2610. if (!isset($this-> frames[$version])) {
2611. $this-> frames[$version] = $this-> createFrame($version);
2612. }
2613. if ( is_null($this-> frames[$version])) {
2614. return NULL;
2615. }
2616. return $this-> frames[$version];
2617. }
2619. /**
2620. * Return block number 0
2621. * @param array $spec
2622. * @return int value
2623. */
2624. protected function rsBlockNum($spec) {
2625. return ($spec[0] + $spec[3]);
2626. }
2628. /**
2629. * Return block number 1
2630. * @param array $spec
2631. * @return int value
2632. */
2633. protected function rsBlockNum1($spec) {
2634. return $spec[0];
2635. }
2637. /**
2638. * Return data codes 1
2639. * @param array $spec
2640. * @return int value
2641. */
2642. protected function rsDataCodes1($spec) {
2643. return $spec[1];
2644. }
2646. /**
2647. * Return ecc codes 1
2648. * @param array $spec
2649. * @return int value
2650. */
2651. protected function rsEccCodes1($spec) {
2652. return $spec[2];
2653. }
2655. /**
2656. * Return block number 2
2657. * @param array $spec
2658. * @return int value
2659. */
2660. protected function rsBlockNum2($spec) {
2661. return $spec[3];
2662. }
2664. /**
2665. * Return data codes 2
2666. * @param array $spec
2667. * @return int value
2668. */
2669. protected function rsDataCodes2($spec) {
2670. return $spec[4];
2671. }
2673. /**
2674. * Return ecc codes 2
2675. * @param array $spec
2676. * @return int value
2677. */
2678. protected function rsEccCodes2($spec) {
2679. return $spec[2];
2680. }
2682. /**
2683. * Return data length
2684. * @param array $spec
2685. * @return int value
2686. */
2687. protected function rsDataLength($spec) {
2688. return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
2689. }
2691. /**
2692. * Return ecc length
2693. * @param array $spec
2694. * @return int value
2695. */
2696. protected function rsEccLength($spec) {
2697. return ($spec[0] + $spec[3]) * $spec[2];
2698. }
2700. // - - - - - - - - - - - - - - - - - - - - - - - - -
2702. // QRrs
2704. /**
2705. * Initialize a Reed-Solomon codec and add it to existing rsitems
2706. * @param int $symsize symbol size, bits
2707. * @param int $gfpoly Field generator polynomial coefficients
2708. * @param int $fcr first root of RS code generator polynomial, index form
2709. * @param int $prim primitive element to generate polynomial roots
2710. * @param int $nroots RS code generator polynomial degree (number of roots)
2711. * @param int $pad padding bytes at front of shortened block
2712. * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2713. */
2714. protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2715. foreach ($this-> rsitems as $rs) {
2716. if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
2717. OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
2718. continue;
2719. }
2720. return $rs;
2721. }
2722. $rs = $this-> init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2723. array_unshift($this-> rsitems, $rs);
2724. return $rs;
2725. }
2727. // - - - - - - - - - - - - - - - - - - - - - - - - -
2729. // QRrsItem
2731. /**
2732. * modnn
2733. * @param array RS values
2734. * @param int $x X position
2735. * @return int X osition
2736. */
2737. protected function modnn($rs, $x) {
2738. while ($x >= $rs['nn']) {
2739. $x -= $rs['nn'];
2740. $x = ($x >> $rs['mm']) + ($x & $rs['nn']);
2741. }
2742. return $x;
2743. }
2745. /**
2746. * Initialize a Reed-Solomon codec and returns an array of values.
2747. * @param int $symsize symbol size, bits
2748. * @param int $gfpoly Field generator polynomial coefficients
2749. * @param int $fcr first root of RS code generator polynomial, index form
2750. * @param int $prim primitive element to generate polynomial roots
2751. * @param int $nroots RS code generator polynomial degree (number of roots)
2752. * @param int $pad padding bytes at front of shortened block
2753. * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2754. */
2755. protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2756. // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
2757. $rs = null;
2758. // Check parameter ranges
2759. if (($symsize < 0) OR ($symsize > 8)) {
2760. return $rs;
2761. }
2762. if (($fcr < 0) OR ($fcr >= (1<<$symsize))) {
2763. return $rs;
2764. }
2765. if (($prim <= 0) OR ($prim >= (1<<$symsize))) {
2766. return $rs;
2767. }
2768. if (($nroots < 0) OR ($nroots >= (1<<$symsize))) {
2769. return $rs;
2770. }
2771. if (($pad < 0) OR ($pad >= ((1<<$symsize) -1 - $nroots))) {
2772. return $rs;
2773. }
2774. $rs = array();
2775. $rs['mm'] = $symsize;
2776. $rs['nn'] = (1 << $symsize) - 1;
2777. $rs['pad'] = $pad;
2778. $rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
2779. $rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
2780. // PHP style macro replacement ;)
2781. $NN =& $rs['nn'];
2782. $A0 =& $NN;
2783. // Generate Galois field lookup tables
2784. $rs['index_of'][0] = $A0; // log(zero) = -inf
2785. $rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
2786. $sr = 1;
2787. for ($i=0; $i<$rs['nn']; ++$i) {
2788. $rs['index_of'][$sr] = $i;
2789. $rs['alpha_to'][$i] = $sr;
2790. $sr <<= 1;
2791. if ($sr & (1 << $symsize)) {
2792. $sr ^= $gfpoly;
2793. }
2794. $sr &= $rs['nn'];
2795. }
2796. if ($sr != 1) {
2797. // field generator polynomial is not primitive!
2798. return NULL;
2799. }
2800. // Form RS code generator polynomial from its roots
2801. $rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
2802. $rs['fcr'] = $fcr;
2803. $rs['prim'] = $prim;
2804. $rs['nroots'] = $nroots;
2805. $rs['gfpoly'] = $gfpoly;
2806. // Find prim-th root of 1, used in decoding
2807. for ($iprim=1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
2808. ; // intentional empty-body loop!
2809. }
2810. $rs['iprim'] = (int)($iprim / $prim);
2811. $rs['genpoly'][0] = 1;
2812. for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
2813. $rs['genpoly'][$i+1] = 1;
2814. // Multiply rs->genpoly[] by @**(root + x)
2815. for ($j = $i; $j > 0; --$j) {
2816. if ($rs['genpoly'][$j] != 0) {
2817. $rs['genpoly'][$j] = $rs['genpoly'][$j-1] ^ $rs['alpha_to'][$this-> modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
2818. } else {
2819. $rs['genpoly'][$j] = $rs['genpoly'][$j-1];
2820. }
2821. }
2822. // rs->genpoly[0] can never be zero
2823. $rs['genpoly'][0] = $rs['alpha_to'][$this-> modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
2824. }
2825. // convert rs->genpoly[] to index form for quicker encoding
2826. for ($i = 0; $i <= $nroots; ++$i) {
2827. $rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
2828. }
2829. return $rs;
2830. }
2832. /**
2833. * Encode a Reed-Solomon codec and returns the parity array
2834. * @param array $rs RS values
2835. * @param array $data data
2836. * @param array $parity parity
2837. * @return parity array
2838. */
2839. protected function encode_rs_char($rs, $data, $parity) {
2840. $MM =& $rs['mm']; // bits per symbol
2841. $NN =& $rs['nn']; // the total number of symbols in a RS block
2842. $ALPHA_TO =& $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form
2843. $INDEX_OF =& $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form
2844. $GENPOLY =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
2845. $NROOTS =& $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block
2846. $FCR =& $rs['fcr']; // first consecutive root, index form
2847. $PRIM =& $rs['prim']; // primitive element, index form
2848. $IPRIM =& $rs['iprim']; // prim-th root of 1, index form
2849. $PAD =& $rs['pad']; // the number of pad symbols in a block
2850. $A0 =& $NN;
2851. $parity = array_fill(0, $NROOTS, 0);
2852. for ($i=0; $i < ($NN - $NROOTS - $PAD); $i++) {
2853. $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2854. if ($feedback != $A0) {
2855. // feedback term is non-zero
2856. // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2857. // always be for the polynomials constructed by init_rs()
2858. $feedback = $this-> modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
2859. for ($j=1; $j < $NROOTS; ++$j) {
2860. $parity[$j] ^= $ALPHA_TO[$this-> modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
2861. }
2862. }
2863. // Shift
2864. array_shift($parity);
2865. if ($feedback != $A0) {
2866. array_push($parity, $ALPHA_TO[$this-> modnn($rs, $feedback + $GENPOLY[0])]);
2867. } else {
2868. array_push($parity, 0);
2869. }
2870. }
2871. return $parity;
2872. }
2874. } // end QRcode class
2876. } // END OF "class_exists QRcode"
2877. //============================================================+
2878. // END OF FILE
2879. //============================================================+

Documentation generated on Sun, 27 Feb 2011 16:33:37 -0800 by phpDocumentor 1.4.3