]>
git.immae.eu Git - github/wallabag/wallabag.git/blob - inc/3rdparty/libraries/tcpdf/include/barcodes/qrcode.php
2 //============================================================+
3 // File name : qrcode.php
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
12 // This file is part of TCPDF software library.
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.
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.
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/>.
27 // See LICENSE.TXT file for more information.
28 // -------------------------------------------------------------------
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
40 // Currently the following features are not supported:
41 // ECI and FNC1 mode, Micro QR Code, QR Code model 1,
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/
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
58 // Reed-Solomon code encoder is written by Phil Karn, KA9Q.
59 // Copyright (C) 2002-2006 Phil Karn, KA9Q
61 // QR Code is registered trademark of DENSO WAVE INCORPORATED
62 // http://www.denso-wave.com/qrcode/index-e.html
63 // ---------------------------------------------------------
64 //============================================================+
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.
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.
77 * @package com.tecnick.tcpdf
78 * @author Nicola Asuni
83 if (! defined ( 'QRCODEDEFS' )) {
86 * Indicate that definitions for this class are set
88 define ( 'QRCODEDEFS' , true );
90 // -----------------------------------------------------
92 // Encoding modes (characters which can be encoded in QRcode)
97 define ( 'QR_MODE_NL' , - 1 );
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.
102 define ( 'QR_MODE_NM' , 0 );
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.
107 define ( 'QR_MODE_AN' , 1 );
110 * Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
112 define ( 'QR_MODE_8B' , 2 );
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.
117 define ( 'QR_MODE_KJ' , 3 );
120 * Encoding mode STRUCTURED (currently unsupported)
122 define ( 'QR_MODE_ST' , 4 );
124 // -----------------------------------------------------
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.
131 * Error correction level L : About 7% or less errors can be corrected.
133 define ( 'QR_ECLEVEL_L' , 0 );
136 * Error correction level M : About 15% or less errors can be corrected.
138 define ( 'QR_ECLEVEL_M' , 1 );
141 * Error correction level Q : About 25% or less errors can be corrected.
143 define ( 'QR_ECLEVEL_Q' , 2 );
146 * Error correction level H : About 30% or less errors can be corrected.
148 define ( 'QR_ECLEVEL_H' , 3 );
150 // -----------------------------------------------------
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.
158 * Maximum QR Code version.
160 define ( 'QRSPEC_VERSION_MAX' , 40 );
163 * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
165 define ( 'QRSPEC_WIDTH_MAX' , 177 );
167 // -----------------------------------------------------
170 * Matrix index to get width from $capacity array.
172 define ( 'QRCAP_WIDTH' , 0 );
175 * Matrix index to get number of words from $capacity array.
177 define ( 'QRCAP_WORDS' , 1 );
180 * Matrix index to get remainder from $capacity array.
182 define ( 'QRCAP_REMINDER' , 2 );
185 * Matrix index to get error correction level from $capacity array.
187 define ( 'QRCAP_EC' , 3 );
189 // -----------------------------------------------------
191 // Structure (currently usupported)
194 * Number of header bits for structured mode
196 define ( 'STRUCTURE_HEADER_BITS' , 20 );
199 * Max number of symbols for structured mode
201 define ( 'MAX_STRUCTURED_SYMBOLS' , 16 );
203 // -----------------------------------------------------
208 * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
213 * Down point base value for case 2 mask pattern (module block of same color)
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)
223 * Down point base value for case 4 mask pattern (ration of dark modules in whole)
227 // -----------------------------------------------------
229 // Optimization settings
232 * if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
234 define ( 'QR_FIND_BEST_MASK' , true );
237 * if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
239 define ( 'QR_FIND_FROM_RANDOM' , 2 );
242 * when QR_FIND_BEST_MASK === false
244 define ( 'QR_DEFAULT_MASK' , 2 );
246 // -----------------------------------------------------
248 } // end of definitions
250 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
252 // for compatibility with PHP4
253 if (! function_exists ( 'str_split' )) {
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.
260 function str_split ( $string , $split_length = 1 ) {
261 if (( strlen ( $string ) > $split_length ) OR (! $split_length )) {
263 $c = strlen ( $string );
264 $parts [] = substr ( $string , 0 , $split_length );
265 $string = substr ( $string , $split_length );
266 } while ( $string !== false );
268 $parts = array ( $string );
274 // #####################################################
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.
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.
287 * @package com.tecnick.tcpdf
288 * @author Nicola Asuni
294 * Barcode array to be returned which is readable by TCPDF.
297 protected $barcode_array = array ();
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.
303 protected $version = 0 ;
306 * Levels of error correction. See definitions for possible values.
309 protected $level = QR_ECLEVEL_L
;
315 protected $hint = QR_MODE_8B
;
318 * Boolean flag, if true the input string will be converted to uppercase.
321 protected $casesensitive = true ;
324 * Structured QR code (not supported yet).
327 protected $structured = 0 ;
373 // ---- QRrawcode ----
379 protected $datacode = array ();
382 * Error correction code.
385 protected $ecccode = array ();
394 * Reed-Solomon blocks.
397 protected $rsblocks = array (); //of RSblock
409 protected $dataLength ;
412 * Error correction length.
415 protected $eccLength ;
429 protected $runLength = array ();
437 protected $dataStr = '' ;
445 // Reed-Solomon items
448 * Reed-Solomon items.
451 protected $rsitems = array ();
457 protected $frames = array ();
460 * Alphabet-numeric convesion table.
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 //
475 * Array Table of the capacity of symbols.
476 * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
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
524 * Array Length indicator.
527 protected $lengthTableBits = array (
535 * Array Table of the error correction code (Reed-Solomon block).
536 * See Table 12-16 (pp.30-36), JIS X0510:2004.
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
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.
589 protected $alignmentPattern = array (
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
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]
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 , //
616 * Array Format information
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 ) //
627 // -------------------------------------------------
628 // -------------------------------------------------
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>
639 public function __construct ( $code , $eclevel = 'L' ) {
640 $barcode_array = array ();
641 if (( is_null ( $code )) OR ( $code == '\0' ) OR ( $code == '' )) {
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
;
649 if (( $this- > hint
!= QR_MODE_8B
) AND ( $this- > hint
!= QR_MODE_KJ
)) {
652 if (( $this- > version
< 0 ) OR ( $this- > version
> QRSPEC_VERSION_MAX
)) {
655 $this- > items
= array ();
656 $this- > encodeString ( $code );
657 if ( is_null ( $this- > data
)) {
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 ) {
667 foreach ( str_split ( $line ) as $char ) {
668 $arrAdd [] = ( $char == '1' )? 1 : 0 ;
670 $barcode_array [ 'bcode' ][] = $arrAdd ;
672 $this- > barcode_array
= $barcode_array ;
676 * Returns a barcode array which is readable by TCPDF
677 * @return array barcode array readable by TCPDF;
680 public function getBarcodeArray () {
681 return $this- > barcode_array
;
685 * Convert the frame in binary form
686 * @param $frame (array) array to binarize
687 * @return array frame in binary form
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' ;
701 * Encode the input string to QR code
702 * @param $string (string) input string to encode
704 protected function encodeString ( $string ) {
705 $this- > dataStr
= $string ;
706 if (! $this- > casesensitive
) {
709 $ret = $this- > splitString ();
713 $this- > encodeMask (- 1 );
718 * @param $mask (int) masking mode
720 protected function encodeMask ( $mask ) {
721 $spec = array ( 0 , 0 , 0 , 0 , 0 );
722 $this- > datacode
= $this- > getByteStream ( $this- > items
);
723 if ( is_null ( $this- > datacode
)) {
726 $spec = $this- > getEccSpec ( $this- > version
, $this- > level
, $spec );
727 $this- > b1
= $this- > rsBlockNum1 ( $spec );
728 $this- > dataLength
= $this- > rsDataLength ( $spec );
729 $this- > eccLength
= $this- > rsEccLength ( $spec );
730 $this- > ecccode
= array_fill ( 0 , $this- > eccLength
, 0 );
731 $this- > blocks
= $this- > rsBlockNum ( $spec );
732 $ret = $this- > init ( $spec );
737 $this- > width
= $this- > getWidth ( $this- > version
);
738 $this- > frame
= $this- > newFrame ( $this- > version
);
739 $this- > x
= $this- > width
- 1 ;
740 $this- > y
= $this- > width
- 1 ;
743 // inteleaved data and ecc codes
744 for ( $i = 0 ; $i < ( $this- > dataLength +
$this- > eccLength
); $i ++
) {
745 $code = $this- > getCode ();
747 for ( $j = 0 ; $j < 8 ; $j ++
) {
748 $addr = $this- > getNextPosition ();
749 $this- > setFrameAt ( $addr , 0x02 | (( $bit & $code ) != 0 ));
754 $j = $this- > getRemainder ( $this- > version
);
755 for ( $i = 0 ; $i < $j ; $i ++
) {
756 $addr = $this- > getNextPosition ();
757 $this- > setFrameAt ( $addr , 0x02 );
760 $this- > runLength
= array_fill ( 0 , QRSPEC_WIDTH_MAX +
1 , 0 );
762 if ( QR_FIND_BEST_MASK
) {
763 $masked = $this- > mask ( $this- > width
, $this- > frame
, $this- > level
);
765 $masked = $this- > makeMask ( $this- > width
, $this- > frame
, ( intval ( QR_DEFAULT_MASK
) %
8 ), $this- > level
);
768 $masked = $this- > makeMask ( $this- > width
, $this- > frame
, $mask , $this- > level
);
770 if ( $masked == NULL ) {
773 $this- > data
= $masked ;
776 // - - - - - - - - - - - - - - - - - - - - - - - - -
781 * Set frame value at specified position
782 * @param $at (array) x,y position
783 * @param $val (int) value of the character to set
785 protected function setFrameAt ( $at , $val ) {
786 $this- > frame
[ $at [ 'y' ]][ $at [ 'x' ]] = chr ( $val );
790 * Get frame value at specified position
791 * @param $at (array) x,y position
792 * @return value at specified position
794 protected function getFrameAt ( $at ) {
795 return ord ( $this- > frame
[ $at [ 'y' ]][ $at [ 'x' ]]);
799 * Return the next frame position
800 * @return array of x,y coordinates
802 protected function getNextPosition () {
804 if ( $this- > bit
== - 1 ) {
806 return array ( 'x' => $this- > x
, 'y' => $this- > y
);
811 if ( $this- > bit
== 0 ) {
819 if ( $this- > dir
< 0 ) {
840 if (( $x < 0 ) OR ( $y < 0 )) {
845 } while ( ord ( $this- > frame
[ $y ][ $x ]) & 0x80 );
846 return array ( 'x' => $x , 'y' => $y );
849 // - - - - - - - - - - - - - - - - - - - - - - - - -
855 * @param $spec (array) array of ECC specification
856 * @return 0 in case of success, -1 in case of error
858 protected function init ( $spec ) {
859 $dl = $this- > rsDataCodes1 ( $spec );
860 $el = $this- > rsEccCodes1 ( $spec );
861 $rs = $this- > init_rs ( 8 , 0x11d , 0 , 1 , $el , 255 - $dl - $el );
865 $endfor = $this- > rsBlockNum1 ( $spec );
866 for ( $i = 0 ; $i < $endfor ; ++
$i ) {
867 $ecc = array_slice ( $this- > ecccode
, $eccPos );
868 $this- > rsblocks
[ $blockNo ] = array ();
869 $this- > rsblocks
[ $blockNo ][ 'dataLength' ] = $dl ;
870 $this- > rsblocks
[ $blockNo ][ 'data' ] = array_slice ( $this- > datacode
, $dataPos );
871 $this- > rsblocks
[ $blockNo ][ 'eccLength' ] = $el ;
872 $ecc = $this- > encode_rs_char ( $rs , $this- > rsblocks
[ $blockNo ][ 'data' ], $ecc );
873 $this- > rsblocks
[ $blockNo ][ 'ecc' ] = $ecc ;
874 $this- > ecccode
= array_merge ( array_slice ( $this- > ecccode
, 0 , $eccPos ), $ecc );
879 if ( $this- > rsBlockNum2 ( $spec ) == 0 ) {
882 $dl = $this- > rsDataCodes2 ( $spec );
883 $el = $this- > rsEccCodes2 ( $spec );
884 $rs = $this- > init_rs ( 8 , 0x11d , 0 , 1 , $el , 255 - $dl - $el );
888 $endfor = $this- > rsBlockNum2 ( $spec );
889 for ( $i = 0 ; $i < $endfor ; ++
$i ) {
890 $ecc = array_slice ( $this- > ecccode
, $eccPos );
891 $this- > rsblocks
[ $blockNo ] = array ();
892 $this- > rsblocks
[ $blockNo ][ 'dataLength' ] = $dl ;
893 $this- > rsblocks
[ $blockNo ][ 'data' ] = array_slice ( $this- > datacode
, $dataPos );
894 $this- > rsblocks
[ $blockNo ][ 'eccLength' ] = $el ;
895 $ecc = $this- > encode_rs_char ( $rs , $this- > rsblocks
[ $blockNo ][ 'data' ], $ecc );
896 $this- > rsblocks
[ $blockNo ][ 'ecc' ] = $ecc ;
897 $this- > ecccode
= array_merge ( array_slice ( $this- > ecccode
, 0 , $eccPos ), $ecc );
906 * Return Reed-Solomon block code.
907 * @return array rsblocks
909 protected function getCode () {
910 if ( $this- > count
< $this- > dataLength
) {
911 $row = $this- > count %
$this- > blocks
;
912 $col = $this- > count
/ $this- > blocks
;
913 if ( $col >= $this- > rsblocks
[ 0 ][ 'dataLength' ]) {
916 $ret = $this- > rsblocks
[ $row ][ 'data' ][ $col ];
917 } elseif ( $this- > count
< $this- > dataLength +
$this- > eccLength
) {
918 $row = ( $this- > count
- $this- > dataLength
) %
$this- > blocks
;
919 $col = ( $this- > count
- $this- > dataLength
) / $this- > blocks
;
920 $ret = $this- > rsblocks
[ $row ][ 'ecc' ][ $col ];
928 // - - - - - - - - - - - - - - - - - - - - - - - - -
933 * Write Format Information on frame and returns the number of black bits
934 * @param $width (int) frame width
935 * @param $frame (array) frame
936 * @param $mask (array) masking mode
937 * @param $level (int) error correction level
940 protected function writeFormatInformation ( $width , & $frame , $mask , $level ) {
942 $format = $this- > getFormatInfo ( $mask , $level );
943 for ( $i = 0 ; $i < 8 ; ++
$i ) {
950 $frame [ 8 ][ $width - 1 - $i ] = chr ( $v );
952 $frame [ $i ][ 8 ] = chr ( $v );
954 $frame [ $i +
1 ][ 8 ] = chr ( $v );
956 $format = $format >> 1 ;
958 for ( $i = 0 ; $i < 7 ; ++
$i ) {
965 $frame [ $width - 7 +
$i ][ 8 ] = chr ( $v );
967 $frame [ 8 ][ 7 ] = chr ( $v );
969 $frame [ 8 ][ 6 - $i ] = chr ( $v );
971 $format = $format >> 1 ;
978 * @param $x (int) X position
979 * @param $y (int) Y position
982 protected function mask0 ( $x , $y ) {
983 return ( $x +
$y ) & 1 ;
988 * @param $x (int) X position
989 * @param $y (int) Y position
992 protected function mask1 ( $x , $y ) {
998 * @param $x (int) X position
999 * @param $y (int) Y position
1002 protected function mask2 ( $x , $y ) {
1008 * @param $x (int) X position
1009 * @param $y (int) Y position
1012 protected function mask3 ( $x , $y ) {
1013 return ( $x +
$y ) %
3 ;
1018 * @param $x (int) X position
1019 * @param $y (int) Y position
1022 protected function mask4 ( $x , $y ) {
1023 return ((( int )( $y / 2 )) +
(( int )( $x / 3 ))) & 1 ;
1028 * @param $x (int) X position
1029 * @param $y (int) Y position
1032 protected function mask5 ( $x , $y ) {
1033 return (( $x * $y ) & 1 ) +
( $x * $y ) %
3 ;
1038 * @param $x (int) X position
1039 * @param $y (int) Y position
1042 protected function mask6 ( $x , $y ) {
1043 return ((( $x * $y ) & 1 ) +
( $x * $y ) %
3 ) & 1 ;
1048 * @param $x (int) X position
1049 * @param $y (int) Y position
1052 protected function mask7 ( $x , $y ) {
1053 return ((( $x * $y ) %
3 ) +
(( $x +
$y ) & 1 )) & 1 ;
1058 * @param $maskNo (int) mask number
1059 * @param $width (int) width
1060 * @param $frame (array) frame
1061 * @return array bitmask
1063 protected function generateMaskNo ( $maskNo , $width , $frame ) {
1064 $bitMask = array_fill ( 0 , $width , array_fill ( 0 , $width , 0 ));
1065 for ( $y = 0 ; $y < $width ; ++
$y ) {
1066 for ( $x = 0 ; $x < $width ; ++
$x ) {
1067 if ( ord ( $frame [ $y ][ $x ]) & 0x80 ) {
1068 $bitMask [ $y ][ $x ] = 0 ;
1070 $maskFunc = call_user_func ( array ( $this , 'mask' . $maskNo ), $x , $y );
1071 $bitMask [ $y ][ $x ] = ( $maskFunc == 0 )? 1 : 0 ;
1080 * @param $maskNo (int)
1081 * @param $width (int)
1084 * @param $maskGenOnly (boolean)
1087 protected function makeMaskNo ( $maskNo , $width , $s , & $d , $maskGenOnly = false ) {
1090 $bitMask = $this- > generateMaskNo ( $maskNo , $width , $s , $d );
1095 for ( $y = 0 ; $y < $width ; ++
$y ) {
1096 for ( $x = 0 ; $x < $width ; ++
$x ) {
1097 if ( $bitMask [ $y ][ $x ] == 1 ) {
1098 $d [ $y ][ $x ] = chr ( ord ( $s [ $y ][ $x ]) ^
(( int )( $bitMask [ $y ][ $x ])));
1100 $b +
= ( int )( ord ( $d [ $y ][ $x ]) & 1 );
1108 * @param $width (int)
1109 * @param $frame (array)
1110 * @param $maskNo (int)
1111 * @param $level (int)
1112 * @return array mask
1114 protected function makeMask ( $width , $frame , $maskNo , $level ) {
1115 $masked = array_fill ( 0 , $width , str_repeat ( "\0" , $width ));
1116 $this- > makeMaskNo ( $maskNo , $width , $frame , $masked );
1117 $this- > writeFormatInformation ( $width , $masked , $maskNo , $level );
1123 * @param $length (int)
1124 * @return int demerit
1126 protected function calcN1N3 ( $length ) {
1128 for ( $i = 0 ; $i < $length ; ++
$i ) {
1129 if ( $this- > runLength
[ $i ] >= 5 ) {
1130 $demerit +
= ( N1 +
( $this- > runLength
[ $i ] - 5 ));
1133 if (( $i >= 3 ) AND ( $i < ( $length-2 )) AND ( $this- > runLength
[ $i ] %
3 == 0 )) {
1134 $fact = ( int )( $this- > runLength
[ $i ] / 3 );
1135 if (( $this- > runLength
[ $i-2 ] == $fact )
1136 AND ( $this- > runLength
[ $i-1 ] == $fact )
1137 AND ( $this- > runLength
[ $i +
1 ] == $fact )
1138 AND ( $this- > runLength
[ $i +
2 ] == $fact )) {
1139 if (( $this- > runLength
[ $i-3 ] < 0 ) OR ( $this- > runLength
[ $i-3 ] >= ( 4 * $fact ))) {
1141 } elseif ((( $i +
3 ) >= $length ) OR ( $this- > runLength
[ $i +
3 ] >= ( 4 * $fact ))) {
1153 * @param $width (int)
1154 * @param $frame (array)
1155 * @return int demerit
1157 protected function evaluateSymbol ( $width , $frame ) {
1160 for ( $y = 0 ; $y < $width ; ++
$y ) {
1162 $this- > runLength
[ 0 ] = 1 ;
1163 $frameY = $frame [ $y ];
1165 $frameYM = $frame [ $y-1 ];
1167 for ( $x = 0 ; $x < $width ; ++
$x ) {
1168 if (( $x > 0 ) AND ( $y > 0 )) {
1169 $b22 = ord ( $frameY [ $x ]) & ord ( $frameY [ $x-1 ]) & ord ( $frameYM [ $x ]) & ord ( $frameYM [ $x-1 ]);
1170 $w22 = ord ( $frameY [ $x ]) | ord ( $frameY [ $x-1 ]) | ord ( $frameYM [ $x ]) | ord ( $frameYM [ $x-1 ]);
1171 if (( $b22 | ( $w22 ^
1 )) & 1 ) {
1175 if (( $x == 0 ) AND ( ord ( $frameY [ $x ]) & 1 )) {
1176 $this- > runLength
[ 0 ] = - 1 ;
1178 $this- > runLength
[ $head ] = 1 ;
1180 if (( ord ( $frameY [ $x ]) ^
ord ( $frameY [ $x-1 ])) & 1 ) {
1182 $this- > runLength
[ $head ] = 1 ;
1184 $this- > runLength
[ $head ] ++
;
1188 $demerit +
= $this- > calcN1N3 ( $head +
1 );
1190 for ( $x = 0 ; $x < $width ; ++
$x ) {
1192 $this- > runLength
[ 0 ] = 1 ;
1193 for ( $y = 0 ; $y < $width ; ++
$y ) {
1194 if (( $y == 0 ) AND ( ord ( $frame [ $y ][ $x ]) & 1 )) {
1195 $this- > runLength
[ 0 ] = - 1 ;
1197 $this- > runLength
[ $head ] = 1 ;
1199 if (( ord ( $frame [ $y ][ $x ]) ^
ord ( $frame [ $y-1 ][ $x ])) & 1 ) {
1201 $this- > runLength
[ $head ] = 1 ;
1203 $this- > runLength
[ $head ] ++
;
1207 $demerit +
= $this- > calcN1N3 ( $head +
1 );
1214 * @param $width (int)
1215 * @param $frame (array)
1216 * @param $level (int)
1217 * @return array best mask
1219 protected function mask ( $width , $frame , $level ) {
1220 $minDemerit = PHP_INT_MAX
;
1222 $bestMask = array ();
1223 $checked_masks = array ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 );
1224 if ( QR_FIND_FROM_RANDOM
!== false ) {
1225 $howManuOut = 8 - ( QR_FIND_FROM_RANDOM %
9 );
1226 for ( $i = 0 ; $i < $howManuOut ; ++
$i ) {
1227 $remPos = rand ( 0 , count ( $checked_masks )- 1 );
1228 unset ( $checked_masks [ $remPos ]);
1229 $checked_masks = array_values ( $checked_masks );
1233 foreach ( $checked_masks as $i ) {
1234 $mask = array_fill ( 0 , $width , str_repeat ( "\0" , $width ));
1237 $blacks = $this- > makeMaskNo ( $i , $width , $frame , $mask );
1238 $blacks +
= $this- > writeFormatInformation ( $width , $mask , $i , $level );
1239 $blacks = ( int )( 100 * $blacks / ( $width * $width ));
1240 $demerit = ( int )(( int )( abs ( $blacks - 50 ) / 5 ) * N4
);
1241 $demerit +
= $this- > evaluateSymbol ( $width , $mask );
1242 if ( $demerit < $minDemerit ) {
1243 $minDemerit = $demerit ;
1251 // - - - - - - - - - - - - - - - - - - - - - - - - -
1256 * Return true if the character at specified position is a number
1257 * @param $str (string) string
1258 * @param $pos (int) characted position
1259 * @return boolean true of false
1261 protected function isdigitat ( $str , $pos ) {
1262 if ( $pos >= strlen ( $str )) {
1265 return (( ord ( $str [ $pos ]) >= ord ( '0' ))&&( ord ( $str [ $pos ]) <= ord ( '9' )));
1269 * Return true if the character at specified position is an alphanumeric character
1270 * @param $str (string) string
1271 * @param $pos (int) characted position
1272 * @return boolean true of false
1274 protected function isalnumat ( $str , $pos ) {
1275 if ( $pos >= strlen ( $str )) {
1278 return ( $this- > lookAnTable ( ord ( $str [ $pos ])) >= 0 );
1286 protected function identifyMode ( $pos ) {
1287 if ( $pos >= strlen ( $this- > dataStr
)) {
1290 $c = $this- > dataStr
[ $pos ];
1291 if ( $this- > isdigitat ( $this- > dataStr
, $pos )) {
1293 } elseif ( $this- > isalnumat ( $this- > dataStr
, $pos )) {
1295 } elseif ( $this- > hint
== QR_MODE_KJ
) {
1296 if ( $pos +
1 < strlen ( $this- > dataStr
)) {
1297 $d = $this- > dataStr
[ $pos +
1 ];
1298 $word = ( ord ( $c ) << 8 ) | ord ( $d );
1299 if (( $word >= 0x8140 && $word <= 0x9ffc ) OR ( $word >= 0xe040 && $word <= 0xebbf )) {
1311 protected function eatNum () {
1312 $ln = $this- > lengthIndicator ( QR_MODE_NM
, $this- > version
);
1314 while ( $this- > isdigitat ( $this- > dataStr
, $p )) {
1318 $mode = $this- > identifyMode ( $p );
1319 if ( $mode == QR_MODE_8B
) {
1320 $dif = $this- > estimateBitsModeNum ( $run ) +
4 +
$ln
1321 +
$this- > estimateBitsMode8 ( 1 ) // + 4 + l8
1322 - $this- > estimateBitsMode8 ( $run +
1 ); // - 4 - l8
1324 return $this- > eat8 ();
1327 if ( $mode == QR_MODE_AN
) {
1328 $dif = $this- > estimateBitsModeNum ( $run ) +
4 +
$ln
1329 +
$this- > estimateBitsModeAn ( 1 ) // + 4 + la
1330 - $this- > estimateBitsModeAn ( $run +
1 ); // - 4 - la
1332 return $this- > eatAn ();
1335 $this- > items
= $this- > appendNewInputItem ( $this- > items
, QR_MODE_NM
, $run , str_split ( $this- > dataStr
));
1343 protected function eatAn () {
1344 $la = $this- > lengthIndicator ( QR_MODE_AN
, $this- > version
);
1345 $ln = $this- > lengthIndicator ( QR_MODE_NM
, $this- > version
);
1347 while ( $this- > isalnumat ( $this- > dataStr
, $p )) {
1348 if ( $this- > isdigitat ( $this- > dataStr
, $p )) {
1350 while ( $this- > isdigitat ( $this- > dataStr
, $q )) {
1353 $dif = $this- > estimateBitsModeAn ( $p ) // + 4 + la
1354 +
$this- > estimateBitsModeNum ( $q - $p ) +
4 +
$ln
1355 - $this- > estimateBitsModeAn ( $q ); // - 4 - la
1366 if (! $this- > isalnumat ( $this- > dataStr
, $p )) {
1367 $dif = $this- > estimateBitsModeAn ( $run ) +
4 +
$la
1368 +
$this- > estimateBitsMode8 ( 1 ) // + 4 + l8
1369 - $this- > estimateBitsMode8 ( $run +
1 ); // - 4 - l8
1371 return $this- > eat8 ();
1374 $this- > items
= $this- > appendNewInputItem ( $this- > items
, QR_MODE_AN
, $run , str_split ( $this- > dataStr
));
1382 protected function eatKanji () {
1384 while ( $this- > identifyMode ( $p ) == QR_MODE_KJ
) {
1387 $this- > items
= $this- > appendNewInputItem ( $this- > items
, QR_MODE_KJ
, $p , str_split ( $this- > dataStr
));
1395 protected function eat8 () {
1396 $la = $this- > lengthIndicator ( QR_MODE_AN
, $this- > version
);
1397 $ln = $this- > lengthIndicator ( QR_MODE_NM
, $this- > version
);
1399 $dataStrLen = strlen ( $this- > dataStr
);
1400 while ( $p < $dataStrLen ) {
1401 $mode = $this- > identifyMode ( $p );
1402 if ( $mode == QR_MODE_KJ
) {
1405 if ( $mode == QR_MODE_NM
) {
1407 while ( $this- > isdigitat ( $this- > dataStr
, $q )) {
1410 $dif = $this- > estimateBitsMode8 ( $p ) // + 4 + l8
1411 +
$this- > estimateBitsModeNum ( $q - $p ) +
4 +
$ln
1412 - $this- > estimateBitsMode8 ( $q ); // - 4 - l8
1418 } elseif ( $mode == QR_MODE_AN
) {
1420 while ( $this- > isalnumat ( $this- > dataStr
, $q )) {
1423 $dif = $this- > estimateBitsMode8 ( $p ) // + 4 + l8
1424 +
$this- > estimateBitsModeAn ( $q - $p ) +
4 +
$la
1425 - $this- > estimateBitsMode8 ( $q ); // - 4 - l8
1436 $this- > items
= $this- > appendNewInputItem ( $this- > items
, QR_MODE_8B
, $run , str_split ( $this- > dataStr
));
1444 protected function splitString () {
1445 while ( strlen ( $this- > dataStr
) > 0 ) {
1446 $mode = $this- > identifyMode ( 0 );
1449 $length = $this- > eatNum ();
1453 $length = $this- > eatAn ();
1457 if ( $hint == QR_MODE_KJ
) {
1458 $length = $this- > eatKanji ();
1460 $length = $this- > eat8 ();
1465 $length = $this- > eat8 ();
1475 $this- > dataStr
= substr ( $this- > dataStr
, $length );
1483 protected function toUpper () {
1484 $stringLen = strlen ( $this- > dataStr
);
1486 while ( $p < $stringLen ) {
1487 $mode = $this- > identifyMode ( substr ( $this- > dataStr
, $p ), $this- > hint
);
1488 if ( $mode == QR_MODE_KJ
) {
1491 if (( ord ( $this- > dataStr
[ $p ]) >= ord ( 'a' )) AND ( ord ( $this- > dataStr
[ $p ]) <= ord ( 'z' ))) {
1492 $this- > dataStr
[ $p ] = chr ( ord ( $this- > dataStr
[ $p ]) - 32 );
1497 return $this- > dataStr
;
1500 // - - - - - - - - - - - - - - - - - - - - - - - - -
1506 * @param $mode (int)
1507 * @param $size (int)
1508 * @param $data (array)
1509 * @param $bstream (array)
1510 * @return array input item
1512 protected function newInputItem ( $mode , $size , $data , $bstream = null ) {
1513 $setData = array_slice ( $data , 0 , $size );
1514 if ( count ( $setData ) < $size ) {
1515 $setData = array_merge ( $setData , array_fill ( 0 , ( $size - count ( $setData )), 0 ));
1517 if (! $this- > check ( $mode , $size , $setData )) {
1520 $inputitem = array ();
1521 $inputitem [ 'mode' ] = $mode ;
1522 $inputitem [ 'size' ] = $size ;
1523 $inputitem [ 'data' ] = $setData ;
1524 $inputitem [ 'bstream' ] = $bstream ;
1530 * @param $inputitem (array)
1531 * @param $version (int)
1532 * @return array input item
1534 protected function encodeModeNum ( $inputitem , $version ) {
1535 $words = ( int )( $inputitem [ 'size' ] / 3 );
1536 $inputitem [ 'bstream' ] = array ();
1538 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , $val );
1539 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], $this- > lengthIndicator ( QR_MODE_NM
, $version ), $inputitem [ 'size' ]);
1540 for ( $i = 0 ; $i < $words ; ++
$i ) {
1541 $val = ( ord ( $inputitem [ 'data' ][ $i * 3 ]) - ord ( '0' )) * 100 ;
1542 $val +
= ( ord ( $inputitem [ 'data' ][ $i * 3 +
1 ]) - ord ( '0' )) * 10 ;
1543 $val +
= ( ord ( $inputitem [ 'data' ][ $i * 3 +
2 ]) - ord ( '0' ));
1544 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 10 , $val );
1546 if ( $inputitem [ 'size' ] - $words * 3 == 1 ) {
1547 $val = ord ( $inputitem [ 'data' ][ $words * 3 ]) - ord ( '0' );
1548 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , $val );
1549 } elseif (( $inputitem [ 'size' ] - ( $words * 3 )) == 2 ) {
1550 $val = ( ord ( $inputitem [ 'data' ][ $words * 3 ]) - ord ( '0' )) * 10 ;
1551 $val +
= ( ord ( $inputitem [ 'data' ][ $words * 3 +
1 ]) - ord ( '0' ));
1552 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 7 , $val );
1559 * @param $inputitem (array)
1560 * @param $version (int)
1561 * @return array input item
1563 protected function encodeModeAn ( $inputitem , $version ) {
1564 $words = ( int )( $inputitem [ 'size' ] / 2 );
1565 $inputitem [ 'bstream' ] = array ();
1566 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , 0x02 );
1567 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], $this- > lengthIndicator ( QR_MODE_AN
, $version ), $inputitem [ 'size' ]);
1568 for ( $i = 0 ; $i < $words ; ++
$i ) {
1569 $val = ( int )( $this- > lookAnTable ( ord ( $inputitem [ 'data' ][ $i * 2 ])) * 45 );
1570 $val +
= ( int )( $this- > lookAnTable ( ord ( $inputitem [ 'data' ][( $i * 2 ) +
1 ])));
1571 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 11 , $val );
1573 if ( $inputitem [ 'size' ] & 1 ) {
1574 $val = $this- > lookAnTable ( ord ( $inputitem [ 'data' ][( $words * 2 )]));
1575 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 6 , $val );
1582 * @param $inputitem (array)
1583 * @param $version (int)
1584 * @return array input item
1586 protected function encodeMode8 ( $inputitem , $version ) {
1587 $inputitem [ 'bstream' ] = array ();
1588 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , 0x4 );
1589 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], $this- > lengthIndicator ( QR_MODE_8B
, $version ), $inputitem [ 'size' ]);
1590 for ( $i = 0 ; $i < $inputitem [ 'size' ]; ++
$i ) {
1591 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 8 , ord ( $inputitem [ 'data' ][ $i ]));
1598 * @param $inputitem (array)
1599 * @param $version (int)
1600 * @return array input item
1602 protected function encodeModeKanji ( $inputitem , $version ) {
1603 $inputitem [ 'bstream' ] = array ();
1604 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , 0x8 );
1605 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], $this- > lengthIndicator ( QR_MODE_KJ
, $version ), ( int )( $inputitem [ 'size' ] / 2 ));
1606 for ( $i = 0 ; $i < $inputitem [ 'size' ]; $i +
= 2 ) {
1607 $val = ( ord ( $inputitem [ 'data' ][ $i ]) << 8 ) | ord ( $inputitem [ 'data' ][ $i +
1 ]);
1608 if ( $val <= 0x9ffc ) {
1613 $h = ( $val >> 8 ) * 0xc0 ;
1614 $val = ( $val & 0xff ) +
$h ;
1615 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 13 , $val );
1621 * encodeModeStructure
1622 * @param $inputitem (array)
1623 * @return array input item
1625 protected function encodeModeStructure ( $inputitem ) {
1626 $inputitem [ 'bstream' ] = array ();
1627 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , 0x03 );
1628 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , ord ( $inputitem [ 'data' ][ 1 ]) - 1 );
1629 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 4 , ord ( $inputitem [ 'data' ][ 0 ]) - 1 );
1630 $inputitem [ 'bstream' ] = $this- > appendNum ( $inputitem [ 'bstream' ], 8 , ord ( $inputitem [ 'data' ][ 2 ]));
1636 * @param $inputitem (array)
1637 * @param $version (int)
1638 * @return array input item
1640 protected function encodeBitStream ( $inputitem , $version ) {
1641 $inputitem [ 'bstream' ] = array ();
1642 $words = $this- > maximumWords ( $inputitem [ 'mode' ], $version );
1643 if ( $inputitem [ 'size' ] > $words ) {
1644 $st1 = $this- > newInputItem ( $inputitem [ 'mode' ], $words , $inputitem [ 'data' ]);
1645 $st2 = $this- > newInputItem ( $inputitem [ 'mode' ], $inputitem [ 'size' ] - $words , array_slice ( $inputitem [ 'data' ], $words ));
1646 $st1 = $this- > encodeBitStream ( $st1 , $version );
1647 $st2 = $this- > encodeBitStream ( $st2 , $version );
1648 $inputitem [ 'bstream' ] = array ();
1649 $inputitem [ 'bstream' ] = $this- > appendBitstream ( $inputitem [ 'bstream' ], $st1 [ 'bstream' ]);
1650 $inputitem [ 'bstream' ] = $this- > appendBitstream ( $inputitem [ 'bstream' ], $st2 [ 'bstream' ]);
1652 switch ( $inputitem [ 'mode' ]) {
1654 $inputitem = $this- > encodeModeNum ( $inputitem , $version );
1658 $inputitem = $this- > encodeModeAn ( $inputitem , $version );
1662 $inputitem = $this- > encodeMode8 ( $inputitem , $version );
1666 $inputitem = $this- > encodeModeKanji ( $inputitem , $version );
1670 $inputitem = $this- > encodeModeStructure ( $inputitem );
1681 // - - - - - - - - - - - - - - - - - - - - - - - - -
1686 * Append data to an input object.
1687 * The data is copied and appended to the input object.
1688 * @param $items (arrray) input items
1689 * @param $mode (int) encoding mode.
1690 * @param $size (int) size of data (byte).
1691 * @param $data (array) array of input data.
1695 protected function appendNewInputItem ( $items , $mode , $size , $data ) {
1696 $newitem = $this- > newInputItem ( $mode , $size , $data );
1697 if (! empty ( $newitem )) {
1698 $items [] = $newitem ;
1704 * insertStructuredAppendHeader
1705 * @param $items (array)
1706 * @param $size (int)
1707 * @param $index (int)
1708 * @param $parity (int)
1709 * @return array items
1711 protected function insertStructuredAppendHeader ( $items , $size , $index , $parity ) {
1712 if ( $size > MAX_STRUCTURED_SYMBOLS
) {
1715 if (( $index <= 0 ) OR ( $index > MAX_STRUCTURED_SYMBOLS
)) {
1718 $buf = array ( $size , $index , $parity );
1719 $entry = $this- > newInputItem ( QR_MODE_ST
, 3 , buf
);
1720 array_unshift ( $items , $entry );
1726 * @param $items (array)
1727 * @return int parity
1729 protected function calcParity ( $items ) {
1731 foreach ( $items as $item ) {
1732 if ( $item [ 'mode' ] != QR_MODE_ST
) {
1733 for ( $i = $item [ 'size' ]- 1 ; $i >= 0 ; -- $i ) {
1734 $parity ^
= $item [ 'data' ][ $i ];
1743 * @param $size (int)
1744 * @param $data (array)
1745 * @return boolean true or false
1747 protected function checkModeNum ( $size , $data ) {
1748 for ( $i = 0 ; $i < $size ; ++
$i ) {
1749 if (( ord ( $data [ $i ]) < ord ( '0' )) OR ( ord ( $data [ $i ]) > ord ( '9' ))){
1757 * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
1758 * @param $c (int) character value
1761 protected function lookAnTable ( $c ) {
1762 return (( $c > 127 )?- 1 : $this- > anTable
[ $c ]);
1767 * @param $size (int)
1768 * @param $data (array)
1769 * @return boolean true or false
1771 protected function checkModeAn ( $size , $data ) {
1772 for ( $i = 0 ; $i < $size ; ++
$i ) {
1773 if ( $this- > lookAnTable ( ord ( $data [ $i ])) == - 1 ) {
1781 * estimateBitsModeNum
1782 * @param $size (int)
1783 * @return int number of bits
1785 protected function estimateBitsModeNum ( $size ) {
1786 $w = ( int )( $size / 3 );
1788 switch ( $size - ( $w * 3 )) {
1802 * estimateBitsModeAn
1803 * @param $size (int)
1804 * @return int number of bits
1806 protected function estimateBitsModeAn ( $size ) {
1807 $bits = ( int )( $size * 5.5 ); // (size / 2 ) * 11
1816 * @param $size (int)
1817 * @return int number of bits
1819 protected function estimateBitsMode8 ( $size ) {
1820 return ( int )( $size * 8 );
1824 * estimateBitsModeKanji
1825 * @param $size (int)
1826 * @return int number of bits
1828 protected function estimateBitsModeKanji ( $size ) {
1829 return ( int )( $size * 6.5 ); // (size / 2 ) * 13
1834 * @param $size (int)
1835 * @param $data (array)
1836 * @return boolean true or false
1838 protected function checkModeKanji ( $size , $data ) {
1842 for ( $i = 0 ; $i < $size ; $i +
= 2 ) {
1843 $val = ( ord ( $data [ $i ]) << 8 ) | ord ( $data [ $i +
1 ]);
1844 if (( $val < 0x8140 ) OR (( $val > 0x9ffc ) AND ( $val < 0xe040 )) OR ( $val > 0xebbf )) {
1852 * Validate the input data.
1853 * @param $mode (int) encoding mode.
1854 * @param $size (int) size of data (byte).
1855 * @param $data (array) data to validate
1856 * @return boolean true in case of valid data, false otherwise
1858 protected function check ( $mode , $size , $data ) {
1864 return $this- > checkModeNum ( $size , $data );
1867 return $this- > checkModeAn ( $size , $data );
1870 return $this- > checkModeKanji ( $size , $data );
1886 * estimateBitStreamSize
1887 * @param $items (array)
1888 * @param $version (int)
1891 protected function estimateBitStreamSize ( $items , $version ) {
1893 if ( $version == 0 ) {
1896 foreach ( $items as $item ) {
1897 switch ( $item [ 'mode' ]) {
1899 $bits = $this- > estimateBitsModeNum ( $item [ 'size' ]);
1903 $bits = $this- > estimateBitsModeAn ( $item [ 'size' ]);
1907 $bits = $this- > estimateBitsMode8 ( $item [ 'size' ]);
1911 $bits = $this- > estimateBitsModeKanji ( $item [ 'size' ]);
1915 return STRUCTURE_HEADER_BITS
;
1921 $l = $this- > lengthIndicator ( $item [ 'mode' ], $version );
1923 $num = ( int )(( $item [ 'size' ] +
$m - 1 ) / $m );
1924 $bits +
= $num * ( 4 +
$l );
1931 * @param $items (array)
1932 * @return int version
1934 protected function estimateVersion ( $items ) {
1939 $bits = $this- > estimateBitStreamSize ( $items , $prev );
1940 $version = $this- > getMinimumVersion (( int )(( $bits +
7 ) / 8 ), $this- > level
);
1944 } while ( $version > $prev );
1950 * @param $mode (int)
1951 * @param $version (int)
1952 * @param $bits (int)
1955 protected function lengthOfCode ( $mode , $version , $bits ) {
1956 $payload = $bits - 4 - $this- > lengthIndicator ( $mode , $version );
1959 $chunks = ( int )( $payload / 10 );
1960 $remain = $payload - $chunks * 10 ;
1961 $size = $chunks * 3 ;
1964 } elseif ( $remain >= 4 ) {
1970 $chunks = ( int )( $payload / 11 );
1971 $remain = $payload - $chunks * 11 ;
1972 $size = $chunks * 2 ;
1979 $size = ( int )( $payload / 8 );
1983 $size = ( int )(( $payload / 13 ) * 2 );
1987 $size = ( int )( $payload / 8 );
1995 $maxsize = $this- > maximumWords ( $mode , $version );
1999 if ( $size > $maxsize ) {
2007 * @param $items (array)
2008 * @return array of items and total bits
2010 protected function createBitStream ( $items ) {
2012 foreach ( $items as $key => $item ) {
2013 $items [ $key ] = $this- > encodeBitStream ( $item , $this- > version
);
2014 $bits = count ( $items [ $key ][ 'bstream' ]);
2017 return array ( $items , $total );
2022 * @param $items (array)
2023 * @return array items
2025 protected function convertData ( $items ) {
2026 $ver = $this- > estimateVersion ( $items );
2027 if ( $ver > $this- > version
) {
2028 $this- > version
= $ver ;
2031 $cbs = $this- > createBitStream ( $items );
2037 $ver = $this- > getMinimumVersion (( int )(( $bits +
7 ) / 8 ), $this- > level
);
2040 } elseif ( $ver > $this- > version
) {
2041 $this- > version
= $ver ;
2050 * Append Padding Bit to bitstream
2051 * @param $bstream (array)
2052 * @return array bitstream
2054 protected function appendPaddingBit ( $bstream ) {
2055 if ( is_null ( $bstream )) {
2058 $bits = count ( $bstream );
2059 $maxwords = $this- > getDataLength ( $this- > version
, $this- > level
);
2060 $maxbits = $maxwords * 8 ;
2061 if ( $maxbits == $bits ) {
2064 if ( $maxbits - $bits < 5 ) {
2065 return $this- > appendNum ( $bstream , $maxbits - $bits , 0 );
2068 $words = ( int )(( $bits +
7 ) / 8 );
2070 $padding = $this- > appendNum ( $padding , $words * 8 - $bits +
4 , 0 );
2071 $padlen = $maxwords - $words ;
2074 for ( $i = 0 ; $i < $padlen ; ++
$i ) {
2075 $padbuf [ $i ] = ( $i & 1 )? 0x11 : 0xec ;
2077 $padding = $this- > appendBytes ( $padding , $padlen , $padbuf );
2079 return $this- > appendBitstream ( $bstream , $padding );
2084 * @param $items (array) items
2085 * @return array bitstream
2087 protected function mergeBitStream ( $items ) {
2088 $items = $this- > convertData ( $items );
2089 if (! is_array ( $items )) {
2093 foreach ( $items as $item ) {
2094 $bstream = $this- > appendBitstream ( $bstream , $item [ 'bstream' ]);
2100 * Returns a stream of bits.
2101 * @param $items (int)
2102 * @return array padded merged byte stream
2104 protected function getBitStream ( $items ) {
2105 $bstream = $this- > mergeBitStream ( $items );
2106 return $this- > appendPaddingBit ( $bstream );
2110 * Pack all bit streams padding bits into a byte array.
2111 * @param $items (int)
2112 * @return array padded merged byte stream
2114 protected function getByteStream ( $items ) {
2115 $bstream = $this- > getBitStream ( $items );
2116 return $this- > bitstreamToByte ( $bstream );
2119 // - - - - - - - - - - - - - - - - - - - - - - - - -
2124 * Return an array with zeros
2125 * @param $setLength (int) array size
2128 protected function allocate ( $setLength ) {
2129 return array_fill ( 0 , $setLength , 0 );
2133 * Return new bitstream from number
2134 * @param $bits (int) number of bits
2135 * @param $num (int) number
2136 * @return array bitstream
2138 protected function newFromNum ( $bits , $num ) {
2139 $bstream = $this- > allocate ( $bits );
2140 $mask = 1 << ( $bits - 1 );
2141 for ( $i = 0 ; $i < $bits ; ++
$i ) {
2153 * Return new bitstream from bytes
2154 * @param $size (int) size
2155 * @param $data (array) bytes
2156 * @return array bitstream
2158 protected function newFromBytes ( $size , $data ) {
2159 $bstream = $this- > allocate ( $size * 8 );
2161 for ( $i = 0 ; $i < $size ; ++
$i ) {
2163 for ( $j = 0 ; $j < 8 ; ++
$j ) {
2164 if ( $data [ $i ] & $mask ) {
2177 * Append one bitstream to another
2178 * @param $bitstream (array) original bitstream
2179 * @param $append (array) bitstream to append
2180 * @return array bitstream
2182 protected function appendBitstream ( $bitstream , $append ) {
2183 if ((! is_array ( $append )) OR ( count ( $append ) == 0 )) {
2186 if ( count ( $bitstream ) == 0 ) {
2189 return array_values ( array_merge ( $bitstream , $append ));
2193 * Append one bitstream created from number to another
2194 * @param $bitstream (array) original bitstream
2195 * @param $bits (int) number of bits
2196 * @param $num (int) number
2197 * @return array bitstream
2199 protected function appendNum ( $bitstream , $bits , $num ) {
2203 $b = $this- > newFromNum ( $bits , $num );
2204 return $this- > appendBitstream ( $bitstream , $b );
2208 * Append one bitstream created from bytes to another
2209 * @param $bitstream (array) original bitstream
2210 * @param $size (int) size
2211 * @param $data (array) bytes
2212 * @return array bitstream
2214 protected function appendBytes ( $bitstream , $size , $data ) {
2218 $b = $this- > newFromBytes ( $size , $data );
2219 return $this- > appendBitstream ( $bitstream , $b );
2223 * Convert bitstream to bytes
2224 * @param $bstream (array) original bitstream
2225 * @return array of bytes
2227 protected function bitstreamToByte ( $bstream ) {
2228 if ( is_null ( $bstream )) {
2231 $size = count ( $bstream );
2235 $data = array_fill ( 0 , ( int )(( $size +
7 ) / 8 ), 0 );
2236 $bytes = ( int )( $size / 8 );
2238 for ( $i = 0 ; $i < $bytes ; $i ++
) {
2240 for ( $j = 0 ; $j < 8 ; $j ++
) {
2249 for ( $j = 0 ; $j <( $size & 7 ); $j ++
) {
2259 // - - - - - - - - - - - - - - - - - - - - - - - - -
2264 * Replace a value on the array at the specified position
2265 * @param $srctab (array)
2266 * @param $x (int) X position
2267 * @param $y (int) Y position
2268 * @param $repl (string) value to replace
2269 * @param $replLen (int) length of the repl string
2270 * @return array srctab
2272 protected function qrstrset ( $srctab , $x , $y , $repl , $replLen = false ) {
2273 $srctab [ $y ] = substr_replace ( $srctab [ $y ], ( $replLen !== false )? substr ( $repl , 0 , $replLen ): $repl , $x , ( $replLen !== false )? $replLen : strlen ( $repl ));
2278 * Return maximum data code length (bytes) for the version.
2279 * @param $version (int) version
2280 * @param $level (int) error correction level
2281 * @return int maximum size (bytes)
2283 protected function getDataLength ( $version , $level ) {
2284 return $this- > capacity
[ $version ][ QRCAP_WORDS
] - $this- > capacity
[ $version ][ QRCAP_EC
][ $level ];
2288 * Return maximum error correction code length (bytes) for the version.
2289 * @param $version (int) version
2290 * @param $level (int) error correction level
2291 * @return int ECC size (bytes)
2293 protected function getECCLength ( $version , $level ){
2294 return $this- > capacity
[ $version ][ QRCAP_EC
][ $level ];
2298 * Return the width of the symbol for the version.
2299 * @param $version (int) version
2302 protected function getWidth ( $version ) {
2303 return $this- > capacity
[ $version ][ QRCAP_WIDTH
];
2307 * Return the numer of remainder bits.
2308 * @param $version (int) version
2309 * @return int number of remainder bits
2311 protected function getRemainder ( $version ) {
2312 return $this- > capacity
[ $version ][ QRCAP_REMINDER
];
2316 * Return a version number that satisfies the input code length.
2317 * @param $size (int) input code length (bytes)
2318 * @param $level (int) error correction level
2319 * @return int version number
2321 protected function getMinimumVersion ( $size , $level ) {
2322 for ( $i = 1 ; $i <= QRSPEC_VERSION_MAX
; ++
$i ) {
2323 $words = ( $this- > capacity
[ $i ][ QRCAP_WORDS
] - $this- > capacity
[ $i ][ QRCAP_EC
][ $level ]);
2324 if ( $words >= $size ) {
2328 // the size of input data is greater than QR capacity, try to lover the error correction mode
2333 * Return the size of length indicator for the mode and version.
2334 * @param $mode (int) encoding mode
2335 * @param $version (int) version
2336 * @return int the size of the appropriate length indicator (bits).
2338 protected function lengthIndicator ( $mode , $version ) {
2339 if ( $mode == QR_MODE_ST
) {
2342 if ( $version <= 9 ) {
2344 } elseif ( $version <= 26 ) {
2349 return $this- > lengthTableBits
[ $mode ][ $l ];
2353 * Return the maximum length for the mode and version.
2354 * @param $mode (int) encoding mode
2355 * @param $version (int) version
2356 * @return int the maximum length (bytes)
2358 protected function maximumWords ( $mode , $version ) {
2359 if ( $mode == QR_MODE_ST
) {
2362 if ( $version <= 9 ) {
2364 } else if ( $version <= 26 ) {
2369 $bits = $this- > lengthTableBits
[ $mode ][ $l ];
2370 $words = ( 1 << $bits ) - 1 ;
2371 if ( $mode == QR_MODE_KJ
) {
2372 $words *= 2 ; // the number of bytes is required
2378 * Return an array of ECC specification.
2379 * @param $version (int) version
2380 * @param $level (int) error correction level
2381 * @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}
2382 * @return array spec
2384 protected function getEccSpec ( $version , $level , $spec ) {
2385 if ( count ( $spec ) < 5 ) {
2386 $spec = array ( 0 , 0 , 0 , 0 , 0 );
2388 $b1 = $this- > eccTable
[ $version ][ $level ][ 0 ];
2389 $b2 = $this- > eccTable
[ $version ][ $level ][ 1 ];
2390 $data = $this- > getDataLength ( $version , $level );
2391 $ecc = $this- > getECCLength ( $version , $level );
2394 $spec [ 1 ] = ( int )( $data / $b1 );
2395 $spec [ 2 ] = ( int )( $ecc / $b1 );
2400 $spec [ 1 ] = ( int )( $data / ( $b1 +
$b2 ));
2401 $spec [ 2 ] = ( int )( $ecc / ( $b1 +
$b2 ));
2403 $spec [ 4 ] = $spec [ 1 ] +
1 ;
2409 * Put an alignment marker.
2410 * @param $frame (array) frame
2411 * @param $ox (int) X center coordinate of the pattern
2412 * @param $oy (int) Y center coordinate of the pattern
2413 * @return array frame
2415 protected function putAlignmentMarker ( $frame , $ox , $oy ) {
2417 " \xa1\xa1\xa1\xa1\xa1 " ,
2418 " \xa1\xa0\xa0\xa0\xa1 " ,
2419 " \xa1\xa0\xa1\xa0\xa1 " ,
2420 " \xa1\xa0\xa0\xa0\xa1 " ,
2421 " \xa1\xa1\xa1\xa1\xa1 "
2425 for ( $y = 0 ; $y < 5 ; $y ++
) {
2426 $frame = $this- > qrstrset ( $frame , $xStart , $yStart +
$y , $finder [ $y ]);
2432 * Put an alignment pattern.
2433 * @param $version (int) version
2434 * @param $frame (array) frame
2435 * @param $width (int) width
2436 * @return array frame
2438 protected function putAlignmentPattern ( $version , $frame , $width ) {
2442 $d = $this- > alignmentPattern
[ $version ][ 1 ] - $this- > alignmentPattern
[ $version ][ 0 ];
2446 $w = ( int )(( $width - $this- > alignmentPattern
[ $version ][ 0 ]) / $d +
2 );
2448 if ( $w * $w - 3 == 1 ) {
2449 $x = $this- > alignmentPattern
[ $version ][ 0 ];
2450 $y = $this- > alignmentPattern
[ $version ][ 0 ];
2451 $frame = $this- > putAlignmentMarker ( $frame , $x , $y );
2454 $cx = $this- > alignmentPattern
[ $version ][ 0 ];
2456 for ( $x = 1 ; $x < $wo ; ++
$x ) {
2457 $frame = $this- > putAlignmentMarker ( $frame , 6 , $cx );
2458 $frame = $this- > putAlignmentMarker ( $frame , $cx , 6 );
2461 $cy = $this- > alignmentPattern
[ $version ][ 0 ];
2462 for ( $y = 0 ; $y < $wo ; ++
$y ) {
2463 $cx = $this- > alignmentPattern
[ $version ][ 0 ];
2464 for ( $x = 0 ; $x < $wo ; ++
$x ) {
2465 $frame = $this- > putAlignmentMarker ( $frame , $cx , $cy );
2474 * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits.
2475 * @param $version (int) version
2476 * @return BCH encoded version information pattern
2478 protected function getVersionPattern ( $version ) {
2479 if (( $version < 7 ) OR ( $version > QRSPEC_VERSION_MAX
)) {
2482 return $this- > versionPattern
[( $version - 7 )];
2486 * Return BCH encoded format information pattern.
2487 * @param $mask (array)
2488 * @param $level (int) error correction level
2489 * @return BCH encoded format information pattern
2491 protected function getFormatInfo ( $mask , $level ) {
2492 if (( $mask < 0 ) OR ( $mask > 7 )) {
2495 if (( $level < 0 ) OR ( $level > 3 )) {
2498 return $this- > formatInfo
[ $level ][ $mask ];
2502 * Put a finder pattern.
2503 * @param $frame (array) frame
2504 * @param $ox (int) X center coordinate of the pattern
2505 * @param $oy (int) Y center coordinate of the pattern
2506 * @return array frame
2508 protected function putFinderPattern ( $frame , $ox , $oy ) {
2510 " \xc1\xc1\xc1\xc1\xc1\xc1\xc1 " ,
2511 " \xc1\xc0\xc0\xc0\xc0\xc0\xc1 " ,
2512 " \xc1\xc0\xc1\xc1\xc1\xc0\xc1 " ,
2513 " \xc1\xc0\xc1\xc1\xc1\xc0\xc1 " ,
2514 " \xc1\xc0\xc1\xc1\xc1\xc0\xc1 " ,
2515 " \xc1\xc0\xc0\xc0\xc0\xc0\xc1 " ,
2516 " \xc1\xc1\xc1\xc1\xc1\xc1\xc1 "
2518 for ( $y = 0 ; $y < 7 ; $y ++
) {
2519 $frame = $this- > qrstrset ( $frame , $ox , ( $oy +
$y ), $finder [ $y ]);
2525 * Return a copy of initialized frame.
2526 * @param $version (int) version
2527 * @return Array of unsigned char.
2529 protected function createFrame ( $version ) {
2530 $width = $this- > capacity
[ $version ][ QRCAP_WIDTH
];
2531 $frameLine = str_repeat ( "\0" , $width );
2532 $frame = array_fill ( 0 , $width , $frameLine );
2534 $frame = $this- > putFinderPattern ( $frame , 0 , 0 );
2535 $frame = $this- > putFinderPattern ( $frame , $width - 7 , 0 );
2536 $frame = $this- > putFinderPattern ( $frame , 0 , $width - 7 );
2538 $yOffset = $width - 7 ;
2539 for ( $y = 0 ; $y < 7 ; ++
$y ) {
2540 $frame [ $y ][ 7 ] = " \xc0 " ;
2541 $frame [ $y ][ $width - 8 ] = " \xc0 " ;
2542 $frame [ $yOffset ][ 7 ] = " \xc0 " ;
2545 $setPattern = str_repeat ( " \xc0 " , 8 );
2546 $frame = $this- > qrstrset ( $frame , 0 , 7 , $setPattern );
2547 $frame = $this- > qrstrset ( $frame , $width-8 , 7 , $setPattern );
2548 $frame = $this- > qrstrset ( $frame , 0 , $width - 8 , $setPattern );
2550 $setPattern = str_repeat ( " \x84 " , 9 );
2551 $frame = $this- > qrstrset ( $frame , 0 , 8 , $setPattern );
2552 $frame = $this- > qrstrset ( $frame , $width - 8 , 8 , $setPattern , 8 );
2553 $yOffset = $width - 8 ;
2554 for ( $y = 0 ; $y < 8 ; ++
$y , ++
$yOffset ) {
2555 $frame [ $y ][ 8 ] = " \x84 " ;
2556 $frame [ $yOffset ][ 8 ] = " \x84 " ;
2560 for ( $i = 1 ; $i < $wo ; ++
$i ) {
2561 $frame [ 6 ][ 7 +
$i ] = chr ( 0x90 | ( $i & 1 ));
2562 $frame [ 7 +
$i ][ 6 ] = chr ( 0x90 | ( $i & 1 ));
2564 // Alignment pattern
2565 $frame = $this- > putAlignmentPattern ( $version , $frame , $width );
2566 // Version information
2567 if ( $version >= 7 ) {
2568 $vinf = $this- > getVersionPattern ( $version );
2570 for ( $x = 0 ; $x < 6 ; ++
$x ) {
2571 for ( $y = 0 ; $y < 3 ; ++
$y ) {
2572 $frame [( $width - 11 ) +
$y ][ $x ] = chr ( 0x88 | ( $v & 1 ));
2577 for ( $y = 0 ; $y < 6 ; ++
$y ) {
2578 for ( $x = 0 ; $x < 3 ; ++
$x ) {
2579 $frame [ $y ][ $x +
( $width - 11 )] = chr ( 0x88 | ( $v & 1 ));
2584 // and a little bit...
2585 $frame [ $width - 8 ][ 8 ] = " \x81 " ;
2590 * Set new frame for the specified version.
2591 * @param $version (int) version
2592 * @return Array of unsigned char.
2594 protected function newFrame ( $version ) {
2595 if (( $version < 1 ) OR ( $version > QRSPEC_VERSION_MAX
)) {
2598 if (! isset ( $this- > frames
[ $version ])) {
2599 $this- > frames
[ $version ] = $this- > createFrame ( $version );
2601 if ( is_null ( $this- > frames
[ $version ])) {
2604 return $this- > frames
[ $version ];
2608 * Return block number 0
2609 * @param $spec (array)
2612 protected function rsBlockNum ( $spec ) {
2613 return ( $spec [ 0 ] +
$spec [ 3 ]);
2617 * Return block number 1
2618 * @param $spec (array)
2621 protected function rsBlockNum1 ( $spec ) {
2626 * Return data codes 1
2627 * @param $spec (array)
2630 protected function rsDataCodes1 ( $spec ) {
2635 * Return ecc codes 1
2636 * @param $spec (array)
2639 protected function rsEccCodes1 ( $spec ) {
2644 * Return block number 2
2645 * @param $spec (array)
2648 protected function rsBlockNum2 ( $spec ) {
2653 * Return data codes 2
2654 * @param $spec (array)
2657 protected function rsDataCodes2 ( $spec ) {
2662 * Return ecc codes 2
2663 * @param $spec (array)
2666 protected function rsEccCodes2 ( $spec ) {
2671 * Return data length
2672 * @param $spec (array)
2675 protected function rsDataLength ( $spec ) {
2676 return ( $spec [ 0 ] * $spec [ 1 ]) +
( $spec [ 3 ] * $spec [ 4 ]);
2681 * @param $spec (array)
2684 protected function rsEccLength ( $spec ) {
2685 return ( $spec [ 0 ] +
$spec [ 3 ]) * $spec [ 2 ];
2688 // - - - - - - - - - - - - - - - - - - - - - - - - -
2693 * Initialize a Reed-Solomon codec and add it to existing rsitems
2694 * @param $symsize (int) symbol size, bits
2695 * @param $gfpoly (int) Field generator polynomial coefficients
2696 * @param $fcr (int) first root of RS code generator polynomial, index form
2697 * @param $prim (int) primitive element to generate polynomial roots
2698 * @param $nroots (int) RS code generator polynomial degree (number of roots)
2699 * @param $pad (int) padding bytes at front of shortened block
2700 * @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>.
2702 protected function init_rs ( $symsize , $gfpoly , $fcr , $prim , $nroots , $pad ) {
2703 foreach ( $this- > rsitems
as $rs ) {
2704 if (( $rs [ 'pad' ] != $pad ) OR ( $rs [ 'nroots' ] != $nroots ) OR ( $rs [ 'mm' ] != $symsize )
2705 OR ( $rs [ 'gfpoly' ] != $gfpoly ) OR ( $rs [ 'fcr' ] != $fcr ) OR ( $rs [ 'prim' ] != $prim )) {
2710 $rs = $this- > init_rs_char ( $symsize , $gfpoly , $fcr , $prim , $nroots , $pad );
2711 array_unshift ( $this- > rsitems
, $rs );
2715 // - - - - - - - - - - - - - - - - - - - - - - - - -
2721 * @param $rs (array) RS values
2722 * @param $x (int) X position
2723 * @return int X osition
2725 protected function modnn ( $rs , $x ) {
2726 while ( $x >= $rs [ 'nn' ]) {
2728 $x = ( $x >> $rs [ 'mm' ]) +
( $x & $rs [ 'nn' ]);
2734 * Initialize a Reed-Solomon codec and returns an array of values.
2735 * @param $symsize (int) symbol size, bits
2736 * @param $gfpoly (int) Field generator polynomial coefficients
2737 * @param $fcr (int) first root of RS code generator polynomial, index form
2738 * @param $prim (int) primitive element to generate polynomial roots
2739 * @param $nroots (int) RS code generator polynomial degree (number of roots)
2740 * @param $pad (int) padding bytes at front of shortened block
2741 * @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>.
2743 protected function init_rs_char ( $symsize , $gfpoly , $fcr , $prim , $nroots , $pad ) {
2744 // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
2746 // Check parameter ranges
2747 if (( $symsize < 0 ) OR ( $symsize > 8 )) {
2750 if (( $fcr < 0 ) OR ( $fcr >= ( 1 << $symsize ))) {
2753 if (( $prim <= 0 ) OR ( $prim >= ( 1 << $symsize ))) {
2756 if (( $nroots < 0 ) OR ( $nroots >= ( 1 << $symsize ))) {
2759 if (( $pad < 0 ) OR ( $pad >= (( 1 << $symsize ) - 1 - $nroots ))) {
2763 $rs [ 'mm' ] = $symsize ;
2764 $rs [ 'nn' ] = ( 1 << $symsize ) - 1 ;
2766 $rs [ 'alpha_to' ] = array_fill ( 0 , ( $rs [ 'nn' ] +
1 ), 0 );
2767 $rs [ 'index_of' ] = array_fill ( 0 , ( $rs [ 'nn' ] +
1 ), 0 );
2768 // PHP style macro replacement ;)
2771 // Generate Galois field lookup tables
2772 $rs [ 'index_of' ][ 0 ] = $A0 ; // log(zero) = -inf
2773 $rs [ 'alpha_to' ][ $A0 ] = 0 ; // alpha**-inf = 0
2775 for ( $i = 0 ; $i < $rs [ 'nn' ]; ++
$i ) {
2776 $rs [ 'index_of' ][ $sr ] = $i ;
2777 $rs [ 'alpha_to' ][ $i ] = $sr ;
2779 if ( $sr & ( 1 << $symsize )) {
2785 // field generator polynomial is not primitive!
2788 // Form RS code generator polynomial from its roots
2789 $rs [ 'genpoly' ] = array_fill ( 0 , ( $nroots +
1 ), 0 );
2791 $rs [ 'prim' ] = $prim ;
2792 $rs [ 'nroots' ] = $nroots ;
2793 $rs [ 'gfpoly' ] = $gfpoly ;
2794 // Find prim-th root of 1, used in decoding
2795 for ( $iprim = 1 ; ( $iprim %
$prim ) != 0 ; $iprim +
= $rs [ 'nn' ]) {
2796 ; // intentional empty-body loop!
2798 $rs [ 'iprim' ] = ( int )( $iprim / $prim );
2799 $rs [ 'genpoly' ][ 0 ] = 1 ;
2800 for ( $i = 0 , $root = $fcr * $prim ; $i < $nroots ; $i ++
, $root +
= $prim ) {
2801 $rs [ 'genpoly' ][ $i +
1 ] = 1 ;
2802 // Multiply rs->genpoly[] by @**(root + x)
2803 for ( $j = $i ; $j > 0 ; -- $j ) {
2804 if ( $rs [ 'genpoly' ][ $j ] != 0 ) {
2805 $rs [ 'genpoly' ][ $j ] = $rs [ 'genpoly' ][ $j-1 ] ^
$rs [ 'alpha_to' ][ $this- > modnn ( $rs , $rs [ 'index_of' ][ $rs [ 'genpoly' ][ $j ]] +
$root )];
2807 $rs [ 'genpoly' ][ $j ] = $rs [ 'genpoly' ][ $j-1 ];
2810 // rs->genpoly[0] can never be zero
2811 $rs [ 'genpoly' ][ 0 ] = $rs [ 'alpha_to' ][ $this- > modnn ( $rs , $rs [ 'index_of' ][ $rs [ 'genpoly' ][ 0 ]] +
$root )];
2813 // convert rs->genpoly[] to index form for quicker encoding
2814 for ( $i = 0 ; $i <= $nroots ; ++
$i ) {
2815 $rs [ 'genpoly' ][ $i ] = $rs [ 'index_of' ][ $rs [ 'genpoly' ][ $i ]];
2821 * Encode a Reed-Solomon codec and returns the parity array
2822 * @param $rs (array) RS values
2823 * @param $data (array) data
2824 * @param $parity (array) parity
2825 * @return parity array
2827 protected function encode_rs_char ( $rs , $data , $parity ) {
2828 $MM =& $rs [ 'mm' ]; // bits per symbol
2829 $NN =& $rs [ 'nn' ]; // the total number of symbols in a RS block
2830 $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
2831 $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
2832 $GENPOLY =& $rs [ 'genpoly' ]; // an array of NROOTS+1 elements containing the generator polynomial in index form
2833 $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
2834 $FCR =& $rs [ 'fcr' ]; // first consecutive root, index form
2835 $PRIM =& $rs [ 'prim' ]; // primitive element, index form
2836 $IPRIM =& $rs [ 'iprim' ]; // prim-th root of 1, index form
2837 $PAD =& $rs [ 'pad' ]; // the number of pad symbols in a block
2839 $parity = array_fill ( 0 , $NROOTS , 0 );
2840 for ( $i = 0 ; $i < ( $NN - $NROOTS - $PAD ); $i ++
) {
2841 $feedback = $INDEX_OF [ $data [ $i ] ^
$parity [ 0 ]];
2842 if ( $feedback != $A0 ) {
2843 // feedback term is non-zero
2844 // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2845 // always be for the polynomials constructed by init_rs()
2846 $feedback = $this- > modnn ( $rs , $NN - $GENPOLY [ $NROOTS ] +
$feedback );
2847 for ( $j = 1 ; $j < $NROOTS ; ++
$j ) {
2848 $parity [ $j ] ^
= $ALPHA_TO [ $this- > modnn ( $rs , $feedback +
$GENPOLY [( $NROOTS - $j )])];
2852 array_shift ( $parity );
2853 if ( $feedback != $A0 ) {
2854 array_push ( $parity , $ALPHA_TO [ $this- > modnn ( $rs , $feedback +
$GENPOLY [ 0 ])]);
2856 array_push ( $parity , 0 );
2862 } // end QRcode class
2864 //============================================================+
2866 //============================================================+