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