]> git.wh0rd.org - tt-rss.git/blob - lib/phpqrcode/phpqrcode.php
strip_harmful_tags: remove data- attributes
[tt-rss.git] / lib / phpqrcode / phpqrcode.php
1 <?php
2
3 /*
4 * PHP QR Code encoder
5 *
6 * This file contains MERGED version of PHP QR Code library.
7 * It was auto-generated from full version for your convenience.
8 *
9 * This merged version was configured to not requre any external files,
10 * with disabled cache, error loging and weker but faster mask matching.
11 * If you need tune it up please use non-merged version.
12 *
13 * For full version, documentation, examples of use please visit:
14 *
15 * http://phpqrcode.sourceforge.net/
16 * https://sourceforge.net/projects/phpqrcode/
17 *
18 * PHP QR Code is distributed under LGPL 3
19 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
20 *
21 * This library is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU Lesser General Public
23 * License as published by the Free Software Foundation; either
24 * version 3 of the License, or any later version.
25 *
26 * This library is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * Lesser General Public License for more details.
30 *
31 * You should have received a copy of the GNU Lesser General Public
32 * License along with this library; if not, write to the Free Software
33 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 */
35
36
37
38 /*
39 * Version: 1.1.4
40 * Build: 2010100721
41 */
42
43
44
45 //---- qrconst.php -----------------------------
46
47
48
49
50
51 /*
52 * PHP QR Code encoder
53 *
54 * Common constants
55 *
56 * Based on libqrencode C library distributed under LGPL 2.1
57 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
58 *
59 * PHP QR Code is distributed under LGPL 3
60 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
61 *
62 * This library is free software; you can redistribute it and/or
63 * modify it under the terms of the GNU Lesser General Public
64 * License as published by the Free Software Foundation; either
65 * version 3 of the License, or any later version.
66 *
67 * This library is distributed in the hope that it will be useful,
68 * but WITHOUT ANY WARRANTY; without even the implied warranty of
69 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
70 * Lesser General Public License for more details.
71 *
72 * You should have received a copy of the GNU Lesser General Public
73 * License along with this library; if not, write to the Free Software
74 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
75 */
76
77 // Encoding modes
78
79 define('QR_MODE_NUL', -1);
80 define('QR_MODE_NUM', 0);
81 define('QR_MODE_AN', 1);
82 define('QR_MODE_8', 2);
83 define('QR_MODE_KANJI', 3);
84 define('QR_MODE_STRUCTURE', 4);
85
86 // Levels of error correction.
87
88 define('QR_ECLEVEL_L', 0);
89 define('QR_ECLEVEL_M', 1);
90 define('QR_ECLEVEL_Q', 2);
91 define('QR_ECLEVEL_H', 3);
92
93 // Supported output formats
94
95 define('QR_FORMAT_TEXT', 0);
96 define('QR_FORMAT_PNG', 1);
97
98 class qrstr {
99 public static function set(&$srctab, $x, $y, $repl, $replLen = false) {
100 $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
101 }
102 }
103
104
105
106 //---- merged_config.php -----------------------------
107
108
109
110
111 /*
112 * PHP QR Code encoder
113 *
114 * Config file, tuned-up for merged verion
115 */
116
117 define('QR_CACHEABLE', false); // use cache - more disk reads but less CPU power, masks and format templates are stored there
118 define('QR_CACHE_DIR', false); // used when QR_CACHEABLE === true
119 define('QR_LOG_DIR', false); // default error logs dir
120
121 define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
122 define('QR_FIND_FROM_RANDOM', 2); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
123 define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
124
125 define('QR_PNG_MAXIMUM_SIZE', 1024); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
126
127
128
129
130 //---- qrtools.php -----------------------------
131
132
133
134
135 /*
136 * PHP QR Code encoder
137 *
138 * Toolset, handy and debug utilites.
139 *
140 * PHP QR Code is distributed under LGPL 3
141 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
142 *
143 * This library is free software; you can redistribute it and/or
144 * modify it under the terms of the GNU Lesser General Public
145 * License as published by the Free Software Foundation; either
146 * version 3 of the License, or any later version.
147 *
148 * This library is distributed in the hope that it will be useful,
149 * but WITHOUT ANY WARRANTY; without even the implied warranty of
150 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
151 * Lesser General Public License for more details.
152 *
153 * You should have received a copy of the GNU Lesser General Public
154 * License along with this library; if not, write to the Free Software
155 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
156 */
157
158 class QRtools {
159
160 //----------------------------------------------------------------------
161 public static function binarize($frame)
162 {
163 $len = count($frame);
164 foreach ($frame as &$frameLine) {
165
166 for($i=0; $i<$len; $i++) {
167 $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
168 }
169 }
170
171 return $frame;
172 }
173
174 //----------------------------------------------------------------------
175 public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037')
176 {
177 $barcode_array = array();
178
179 if (!is_array($mode))
180 $mode = explode(',', $mode);
181
182 $eccLevel = 'L';
183
184 if (count($mode) > 1) {
185 $eccLevel = $mode[1];
186 }
187
188 $qrTab = QRcode::text($code, false, $eccLevel);
189 $size = count($qrTab);
190
191 $barcode_array['num_rows'] = $size;
192 $barcode_array['num_cols'] = $size;
193 $barcode_array['bcode'] = array();
194
195 foreach ($qrTab as $line) {
196 $arrAdd = array();
197 foreach(str_split($line) as $char)
198 $arrAdd[] = ($char=='1')?1:0;
199 $barcode_array['bcode'][] = $arrAdd;
200 }
201
202 return $barcode_array;
203 }
204
205 //----------------------------------------------------------------------
206 public static function clearCache()
207 {
208 self::$frames = array();
209 }
210
211 //----------------------------------------------------------------------
212 public static function buildCache()
213 {
214 QRtools::markTime('before_build_cache');
215
216 $mask = new QRmask();
217 for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) {
218 $frame = QRspec::newFrame($a);
219 if (QR_IMAGE) {
220 $fileName = QR_CACHE_DIR.'frame_'.$a.'.png';
221 QRimage::png(self::binarize($frame), $fileName, 1, 0);
222 }
223
224 $width = count($frame);
225 $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
226 for ($maskNo=0; $maskNo<8; $maskNo++)
227 $mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true);
228 }
229
230 QRtools::markTime('after_build_cache');
231 }
232
233 //----------------------------------------------------------------------
234 public static function log($outfile, $err)
235 {
236 if (QR_LOG_DIR !== false) {
237 if ($err != '') {
238 if ($outfile !== false) {
239 file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
240 } else {
241 file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
242 }
243 }
244 }
245 }
246
247 //----------------------------------------------------------------------
248 public static function dumpMask($frame)
249 {
250 $width = count($frame);
251 for($y=0;$y<$width;$y++) {
252 for($x=0;$x<$width;$x++) {
253 echo ord($frame[$y][$x]).',';
254 }
255 }
256 }
257
258 //----------------------------------------------------------------------
259 public static function markTime($markerId)
260 {
261 list($usec, $sec) = explode(" ", microtime());
262 $time = ((float)$usec + (float)$sec);
263
264 if (!isset($GLOBALS['qr_time_bench']))
265 $GLOBALS['qr_time_bench'] = array();
266
267 $GLOBALS['qr_time_bench'][$markerId] = $time;
268 }
269
270 //----------------------------------------------------------------------
271 public static function timeBenchmark()
272 {
273 self::markTime('finish');
274
275 $lastTime = 0;
276 $startTime = 0;
277 $p = 0;
278
279 echo '<table cellpadding="3" cellspacing="1">
280 <thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
281 <tbody>';
282
283 foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {
284 if ($p > 0) {
285 echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>';
286 } else {
287 $startTime = $thisTime;
288 }
289
290 $p++;
291 $lastTime = $thisTime;
292 }
293
294 echo '</tbody><tfoot>
295 <tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>
296 </tfoot>
297 </table>';
298 }
299
300 }
301
302 //##########################################################################
303
304 QRtools::markTime('start');
305
306
307
308
309 //---- qrspec.php -----------------------------
310
311
312
313
314 /*
315 * PHP QR Code encoder
316 *
317 * QR Code specifications
318 *
319 * Based on libqrencode C library distributed under LGPL 2.1
320 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
321 *
322 * PHP QR Code is distributed under LGPL 3
323 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
324 *
325 * The following data / specifications are taken from
326 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
327 * or
328 * "Automatic identification and data capture techniques --
329 * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
330 *
331 * This library is free software; you can redistribute it and/or
332 * modify it under the terms of the GNU Lesser General Public
333 * License as published by the Free Software Foundation; either
334 * version 3 of the License, or any later version.
335 *
336 * This library is distributed in the hope that it will be useful,
337 * but WITHOUT ANY WARRANTY; without even the implied warranty of
338 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
339 * Lesser General Public License for more details.
340 *
341 * You should have received a copy of the GNU Lesser General Public
342 * License along with this library; if not, write to the Free Software
343 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
344 */
345
346 define('QRSPEC_VERSION_MAX', 40);
347 define('QRSPEC_WIDTH_MAX', 177);
348
349 define('QRCAP_WIDTH', 0);
350 define('QRCAP_WORDS', 1);
351 define('QRCAP_REMINDER', 2);
352 define('QRCAP_EC', 3);
353
354 class QRspec {
355
356 public static $capacity = array(
357 array( 0, 0, 0, array( 0, 0, 0, 0)),
358 array( 21, 26, 0, array( 7, 10, 13, 17)), // 1
359 array( 25, 44, 7, array( 10, 16, 22, 28)),
360 array( 29, 70, 7, array( 15, 26, 36, 44)),
361 array( 33, 100, 7, array( 20, 36, 52, 64)),
362 array( 37, 134, 7, array( 26, 48, 72, 88)), // 5
363 array( 41, 172, 7, array( 36, 64, 96, 112)),
364 array( 45, 196, 0, array( 40, 72, 108, 130)),
365 array( 49, 242, 0, array( 48, 88, 132, 156)),
366 array( 53, 292, 0, array( 60, 110, 160, 192)),
367 array( 57, 346, 0, array( 72, 130, 192, 224)), //10
368 array( 61, 404, 0, array( 80, 150, 224, 264)),
369 array( 65, 466, 0, array( 96, 176, 260, 308)),
370 array( 69, 532, 0, array( 104, 198, 288, 352)),
371 array( 73, 581, 3, array( 120, 216, 320, 384)),
372 array( 77, 655, 3, array( 132, 240, 360, 432)), //15
373 array( 81, 733, 3, array( 144, 280, 408, 480)),
374 array( 85, 815, 3, array( 168, 308, 448, 532)),
375 array( 89, 901, 3, array( 180, 338, 504, 588)),
376 array( 93, 991, 3, array( 196, 364, 546, 650)),
377 array( 97, 1085, 3, array( 224, 416, 600, 700)), //20
378 array(101, 1156, 4, array( 224, 442, 644, 750)),
379 array(105, 1258, 4, array( 252, 476, 690, 816)),
380 array(109, 1364, 4, array( 270, 504, 750, 900)),
381 array(113, 1474, 4, array( 300, 560, 810, 960)),
382 array(117, 1588, 4, array( 312, 588, 870, 1050)), //25
383 array(121, 1706, 4, array( 336, 644, 952, 1110)),
384 array(125, 1828, 4, array( 360, 700, 1020, 1200)),
385 array(129, 1921, 3, array( 390, 728, 1050, 1260)),
386 array(133, 2051, 3, array( 420, 784, 1140, 1350)),
387 array(137, 2185, 3, array( 450, 812, 1200, 1440)), //30
388 array(141, 2323, 3, array( 480, 868, 1290, 1530)),
389 array(145, 2465, 3, array( 510, 924, 1350, 1620)),
390 array(149, 2611, 3, array( 540, 980, 1440, 1710)),
391 array(153, 2761, 3, array( 570, 1036, 1530, 1800)),
392 array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35
393 array(161, 3034, 0, array( 600, 1120, 1680, 1980)),
394 array(165, 3196, 0, array( 630, 1204, 1770, 2100)),
395 array(169, 3362, 0, array( 660, 1260, 1860, 2220)),
396 array(173, 3532, 0, array( 720, 1316, 1950, 2310)),
397 array(177, 3706, 0, array( 750, 1372, 2040, 2430)) //40
398 );
399
400 //----------------------------------------------------------------------
401 public static function getDataLength($version, $level)
402 {
403 return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level];
404 }
405
406 //----------------------------------------------------------------------
407 public static function getECCLength($version, $level)
408 {
409 return self::$capacity[$version][QRCAP_EC][$level];
410 }
411
412 //----------------------------------------------------------------------
413 public static function getWidth($version)
414 {
415 return self::$capacity[$version][QRCAP_WIDTH];
416 }
417
418 //----------------------------------------------------------------------
419 public static function getRemainder($version)
420 {
421 return self::$capacity[$version][QRCAP_REMINDER];
422 }
423
424 //----------------------------------------------------------------------
425 public static function getMinimumVersion($size, $level)
426 {
427
428 for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) {
429 $words = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level];
430 if($words >= $size)
431 return $i;
432 }
433
434 return -1;
435 }
436
437 //######################################################################
438
439 public static $lengthTableBits = array(
440 array(10, 12, 14),
441 array( 9, 11, 13),
442 array( 8, 16, 16),
443 array( 8, 10, 12)
444 );
445
446 //----------------------------------------------------------------------
447 public static function lengthIndicator($mode, $version)
448 {
449 if ($mode == QR_MODE_STRUCTURE)
450 return 0;
451
452 if ($version <= 9) {
453 $l = 0;
454 } else if ($version <= 26) {
455 $l = 1;
456 } else {
457 $l = 2;
458 }
459
460 return self::$lengthTableBits[$mode][$l];
461 }
462
463 //----------------------------------------------------------------------
464 public static function maximumWords($mode, $version)
465 {
466 if($mode == QR_MODE_STRUCTURE)
467 return 3;
468
469 if($version <= 9) {
470 $l = 0;
471 } else if($version <= 26) {
472 $l = 1;
473 } else {
474 $l = 2;
475 }
476
477 $bits = self::$lengthTableBits[$mode][$l];
478 $words = (1 << $bits) - 1;
479
480 if($mode == QR_MODE_KANJI) {
481 $words *= 2; // the number of bytes is required
482 }
483
484 return $words;
485 }
486
487 // Error correction code -----------------------------------------------
488 // Table of the error correction code (Reed-Solomon block)
489 // See Table 12-16 (pp.30-36), JIS X0510:2004.
490
491 public static $eccTable = array(
492 array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)),
493 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1
494 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)),
495 array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)),
496 array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)),
497 array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5
498 array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)),
499 array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)),
500 array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)),
501 array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)),
502 array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), //10
503 array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)),
504 array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)),
505 array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)),
506 array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)),
507 array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), //15
508 array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)),
509 array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)),
510 array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)),
511 array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)),
512 array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), //20
513 array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)),
514 array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)),
515 array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)),
516 array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)),
517 array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), //25
518 array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)),
519 array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)),
520 array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)),
521 array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)),
522 array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30
523 array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)),
524 array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)),
525 array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)),
526 array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)),
527 array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), //35
528 array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)),
529 array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)),
530 array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)),
531 array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)),
532 array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)),//40
533 );
534
535 //----------------------------------------------------------------------
536 // CACHEABLE!!!
537
538 public static function getEccSpec($version, $level, array &$spec)
539 {
540 if (count($spec) < 5) {
541 $spec = array(0,0,0,0,0);
542 }
543
544 $b1 = self::$eccTable[$version][$level][0];
545 $b2 = self::$eccTable[$version][$level][1];
546 $data = self::getDataLength($version, $level);
547 $ecc = self::getECCLength($version, $level);
548
549 if($b2 == 0) {
550 $spec[0] = $b1;
551 $spec[1] = (int)($data / $b1);
552 $spec[2] = (int)($ecc / $b1);
553 $spec[3] = 0;
554 $spec[4] = 0;
555 } else {
556 $spec[0] = $b1;
557 $spec[1] = (int)($data / ($b1 + $b2));
558 $spec[2] = (int)($ecc / ($b1 + $b2));
559 $spec[3] = $b2;
560 $spec[4] = $spec[1] + 1;
561 }
562 }
563
564 // Alignment pattern ---------------------------------------------------
565
566 // Positions of alignment patterns.
567 // This array includes only the second and the third position of the
568 // alignment patterns. Rest of them can be calculated from the distance
569 // between them.
570
571 // See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
572
573 public static $alignmentPattern = array(
574 array( 0, 0),
575 array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
576 array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
577 array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15
578 array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20
579 array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25
580 array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30
581 array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35
582 array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40
583 );
584
585
586 /** --------------------------------------------------------------------
587 * Put an alignment marker.
588 * @param frame
589 * @param width
590 * @param ox,oy center coordinate of the pattern
591 */
592 public static function putAlignmentMarker(array &$frame, $ox, $oy)
593 {
594 $finder = array(
595 "\xa1\xa1\xa1\xa1\xa1",
596 "\xa1\xa0\xa0\xa0\xa1",
597 "\xa1\xa0\xa1\xa0\xa1",
598 "\xa1\xa0\xa0\xa0\xa1",
599 "\xa1\xa1\xa1\xa1\xa1"
600 );
601
602 $yStart = $oy-2;
603 $xStart = $ox-2;
604
605 for($y=0; $y<5; $y++) {
606 QRstr::set($frame, $xStart, $yStart+$y, $finder[$y]);
607 }
608 }
609
610 //----------------------------------------------------------------------
611 public static function putAlignmentPattern($version, &$frame, $width)
612 {
613 if($version < 2)
614 return;
615
616 $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0];
617 if($d < 0) {
618 $w = 2;
619 } else {
620 $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2);
621 }
622
623 if($w * $w - 3 == 1) {
624 $x = self::$alignmentPattern[$version][0];
625 $y = self::$alignmentPattern[$version][0];
626 self::putAlignmentMarker($frame, $x, $y);
627 return;
628 }
629
630 $cx = self::$alignmentPattern[$version][0];
631 for($x=1; $x<$w - 1; $x++) {
632 self::putAlignmentMarker($frame, 6, $cx);
633 self::putAlignmentMarker($frame, $cx, 6);
634 $cx += $d;
635 }
636
637 $cy = self::$alignmentPattern[$version][0];
638 for($y=0; $y<$w-1; $y++) {
639 $cx = self::$alignmentPattern[$version][0];
640 for($x=0; $x<$w-1; $x++) {
641 self::putAlignmentMarker($frame, $cx, $cy);
642 $cx += $d;
643 }
644 $cy += $d;
645 }
646 }
647
648 // Version information pattern -----------------------------------------
649
650 // Version information pattern (BCH coded).
651 // See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
652
653 // size: [QRSPEC_VERSION_MAX - 6]
654
655 public static $versionPattern = array(
656 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
657 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
658 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
659 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
660 0x27541, 0x28c69
661 );
662
663 //----------------------------------------------------------------------
664 public static function getVersionPattern($version)
665 {
666 if($version < 7 || $version > QRSPEC_VERSION_MAX)
667 return 0;
668
669 return self::$versionPattern[$version -7];
670 }
671
672 // Format information --------------------------------------------------
673 // See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)
674
675 public static $formatInfo = array(
676 array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976),
677 array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0),
678 array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed),
679 array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)
680 );
681
682 public static function getFormatInfo($mask, $level)
683 {
684 if($mask < 0 || $mask > 7)
685 return 0;
686
687 if($level < 0 || $level > 3)
688 return 0;
689
690 return self::$formatInfo[$level][$mask];
691 }
692
693 // Frame ---------------------------------------------------------------
694 // Cache of initial frames.
695
696 public static $frames = array();
697
698 /** --------------------------------------------------------------------
699 * Put a finder pattern.
700 * @param frame
701 * @param width
702 * @param ox,oy upper-left coordinate of the pattern
703 */
704 public static function putFinderPattern(&$frame, $ox, $oy)
705 {
706 $finder = array(
707 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
708 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
709 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
710 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
711 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
712 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
713 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
714 );
715
716 for($y=0; $y<7; $y++) {
717 QRstr::set($frame, $ox, $oy+$y, $finder[$y]);
718 }
719 }
720
721 //----------------------------------------------------------------------
722 public static function createFrame($version)
723 {
724 $width = self::$capacity[$version][QRCAP_WIDTH];
725 $frameLine = str_repeat ("\0", $width);
726 $frame = array_fill(0, $width, $frameLine);
727
728 // Finder pattern
729 self::putFinderPattern($frame, 0, 0);
730 self::putFinderPattern($frame, $width - 7, 0);
731 self::putFinderPattern($frame, 0, $width - 7);
732
733 // Separator
734 $yOffset = $width - 7;
735
736 for($y=0; $y<7; $y++) {
737 $frame[$y][7] = "\xc0";
738 $frame[$y][$width - 8] = "\xc0";
739 $frame[$yOffset][7] = "\xc0";
740 $yOffset++;
741 }
742
743 $setPattern = str_repeat("\xc0", 8);
744
745 QRstr::set($frame, 0, 7, $setPattern);
746 QRstr::set($frame, $width-8, 7, $setPattern);
747 QRstr::set($frame, 0, $width - 8, $setPattern);
748
749 // Format info
750 $setPattern = str_repeat("\x84", 9);
751 QRstr::set($frame, 0, 8, $setPattern);
752 QRstr::set($frame, $width - 8, 8, $setPattern, 8);
753
754 $yOffset = $width - 8;
755
756 for($y=0; $y<8; $y++,$yOffset++) {
757 $frame[$y][8] = "\x84";
758 $frame[$yOffset][8] = "\x84";
759 }
760
761 // Timing pattern
762
763 for($i=1; $i<$width-15; $i++) {
764 $frame[6][7+$i] = chr(0x90 | ($i & 1));
765 $frame[7+$i][6] = chr(0x90 | ($i & 1));
766 }
767
768 // Alignment pattern
769 self::putAlignmentPattern($version, $frame, $width);
770
771 // Version information
772 if($version >= 7) {
773 $vinf = self::getVersionPattern($version);
774
775 $v = $vinf;
776
777 for($x=0; $x<6; $x++) {
778 for($y=0; $y<3; $y++) {
779 $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
780 $v = $v >> 1;
781 }
782 }
783
784 $v = $vinf;
785 for($y=0; $y<6; $y++) {
786 for($x=0; $x<3; $x++) {
787 $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
788 $v = $v >> 1;
789 }
790 }
791 }
792
793 // and a little bit...
794 $frame[$width - 8][8] = "\x81";
795
796 return $frame;
797 }
798
799 //----------------------------------------------------------------------
800 public static function debug($frame, $binary_mode = false)
801 {
802 if ($binary_mode) {
803
804 foreach ($frame as &$frameLine) {
805 $frameLine = join('<span class="m">&nbsp;&nbsp;</span>', explode('0', $frameLine));
806 $frameLine = join('&#9608;&#9608;', explode('1', $frameLine));
807 }
808
809 ?>
810 <style>
811 .m { background-color: white; }
812 </style>
813 <?php
814 echo '<pre><tt><br/ ><br/ ><br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
815 echo join("<br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", $frame);
816 echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';
817
818 } else {
819
820 foreach ($frame as &$frameLine) {
821 $frameLine = join('<span class="m">&nbsp;</span>', explode("\xc0", $frameLine));
822 $frameLine = join('<span class="m">&#9618;</span>', explode("\xc1", $frameLine));
823 $frameLine = join('<span class="p">&nbsp;</span>', explode("\xa0", $frameLine));
824 $frameLine = join('<span class="p">&#9618;</span>', explode("\xa1", $frameLine));
825 $frameLine = join('<span class="s">&#9671;</span>', explode("\x84", $frameLine)); //format 0
826 $frameLine = join('<span class="s">&#9670;</span>', explode("\x85", $frameLine)); //format 1
827 $frameLine = join('<span class="x">&#9762;</span>', explode("\x81", $frameLine)); //special bit
828 $frameLine = join('<span class="c">&nbsp;</span>', explode("\x90", $frameLine)); //clock 0
829 $frameLine = join('<span class="c">&#9719;</span>', explode("\x91", $frameLine)); //clock 1
830 $frameLine = join('<span class="f">&nbsp;</span>', explode("\x88", $frameLine)); //version
831 $frameLine = join('<span class="f">&#9618;</span>', explode("\x89", $frameLine)); //version
832 $frameLine = join('&#9830;', explode("\x01", $frameLine));
833 $frameLine = join('&#8901;', explode("\0", $frameLine));
834 }
835
836 ?>
837 <style>
838 .p { background-color: yellow; }
839 .m { background-color: #00FF00; }
840 .s { background-color: #FF0000; }
841 .c { background-color: aqua; }
842 .x { background-color: pink; }
843 .f { background-color: gold; }
844 </style>
845 <?php
846 echo "<pre><tt>";
847 echo join("<br/ >", $frame);
848 echo "</tt></pre>";
849
850 }
851 }
852
853 //----------------------------------------------------------------------
854 public static function serial($frame)
855 {
856 return gzcompress(join("\n", $frame), 9);
857 }
858
859 //----------------------------------------------------------------------
860 public static function unserial($code)
861 {
862 return explode("\n", gzuncompress($code));
863 }
864
865 //----------------------------------------------------------------------
866 public static function newFrame($version)
867 {
868 if($version < 1 || $version > QRSPEC_VERSION_MAX)
869 return null;
870
871 if(!isset(self::$frames[$version])) {
872
873 $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat';
874
875 if (QR_CACHEABLE) {
876 if (file_exists($fileName)) {
877 self::$frames[$version] = self::unserial(file_get_contents($fileName));
878 } else {
879 self::$frames[$version] = self::createFrame($version);
880 file_put_contents($fileName, self::serial(self::$frames[$version]));
881 }
882 } else {
883 self::$frames[$version] = self::createFrame($version);
884 }
885 }
886
887 if(is_null(self::$frames[$version]))
888 return null;
889
890 return self::$frames[$version];
891 }
892
893 //----------------------------------------------------------------------
894 public static function rsBlockNum($spec) { return $spec[0] + $spec[3]; }
895 public static function rsBlockNum1($spec) { return $spec[0]; }
896 public static function rsDataCodes1($spec) { return $spec[1]; }
897 public static function rsEccCodes1($spec) { return $spec[2]; }
898 public static function rsBlockNum2($spec) { return $spec[3]; }
899 public static function rsDataCodes2($spec) { return $spec[4]; }
900 public static function rsEccCodes2($spec) { return $spec[2]; }
901 public static function rsDataLength($spec) { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); }
902 public static function rsEccLength($spec) { return ($spec[0] + $spec[3]) * $spec[2]; }
903
904 }
905
906
907
908 //---- qrimage.php -----------------------------
909
910
911
912
913 /*
914 * PHP QR Code encoder
915 *
916 * Image output of code using GD2
917 *
918 * PHP QR Code is distributed under LGPL 3
919 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
920 *
921 * This library is free software; you can redistribute it and/or
922 * modify it under the terms of the GNU Lesser General Public
923 * License as published by the Free Software Foundation; either
924 * version 3 of the License, or any later version.
925 *
926 * This library is distributed in the hope that it will be useful,
927 * but WITHOUT ANY WARRANTY; without even the implied warranty of
928 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
929 * Lesser General Public License for more details.
930 *
931 * You should have received a copy of the GNU Lesser General Public
932 * License along with this library; if not, write to the Free Software
933 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
934 */
935
936 define('QR_IMAGE', true);
937
938 class QRimage {
939
940 //----------------------------------------------------------------------
941 public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE)
942 {
943 $image = self::image($frame, $pixelPerPoint, $outerFrame);
944
945 if ($filename === false) {
946 Header("Content-type: image/png");
947 ImagePng($image);
948 } else {
949 if($saveandprint===TRUE){
950 ImagePng($image, $filename);
951 header("Content-type: image/png");
952 ImagePng($image);
953 }else{
954 ImagePng($image, $filename);
955 }
956 }
957
958 ImageDestroy($image);
959 }
960
961 //----------------------------------------------------------------------
962 public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85)
963 {
964 $image = self::image($frame, $pixelPerPoint, $outerFrame);
965
966 if ($filename === false) {
967 Header("Content-type: image/jpeg");
968 ImageJpeg($image, null, $q);
969 } else {
970 ImageJpeg($image, $filename, $q);
971 }
972
973 ImageDestroy($image);
974 }
975
976 //----------------------------------------------------------------------
977 private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4)
978 {
979 $h = count($frame);
980 $w = strlen($frame[0]);
981
982 $imgW = $w + 2*$outerFrame;
983 $imgH = $h + 2*$outerFrame;
984
985 $base_image =ImageCreate($imgW, $imgH);
986
987 $col[0] = ImageColorAllocate($base_image,255,255,255);
988 $col[1] = ImageColorAllocate($base_image,0,0,0);
989
990 imagefill($base_image, 0, 0, $col[0]);
991
992 for($y=0; $y<$h; $y++) {
993 for($x=0; $x<$w; $x++) {
994 if ($frame[$y][$x] == '1') {
995 ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]);
996 }
997 }
998 }
999
1000 $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
1001 ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
1002 ImageDestroy($base_image);
1003
1004 return $target_image;
1005 }
1006 }
1007
1008
1009
1010 //---- qrinput.php -----------------------------
1011
1012
1013
1014
1015 /*
1016 * PHP QR Code encoder
1017 *
1018 * Input encoding class
1019 *
1020 * Based on libqrencode C library distributed under LGPL 2.1
1021 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
1022 *
1023 * PHP QR Code is distributed under LGPL 3
1024 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
1025 *
1026 * This library is free software; you can redistribute it and/or
1027 * modify it under the terms of the GNU Lesser General Public
1028 * License as published by the Free Software Foundation; either
1029 * version 3 of the License, or any later version.
1030 *
1031 * This library is distributed in the hope that it will be useful,
1032 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1034 * Lesser General Public License for more details.
1035 *
1036 * You should have received a copy of the GNU Lesser General Public
1037 * License along with this library; if not, write to the Free Software
1038 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1039 */
1040
1041 define('STRUCTURE_HEADER_BITS', 20);
1042 define('MAX_STRUCTURED_SYMBOLS', 16);
1043
1044 class QRinputItem {
1045
1046 public $mode;
1047 public $size;
1048 public $data;
1049 public $bstream;
1050
1051 public function __construct($mode, $size, $data, $bstream = null)
1052 {
1053 $setData = array_slice($data, 0, $size);
1054
1055 if (count($setData) < $size) {
1056 $setData = array_merge($setData, array_fill(0,$size-count($setData),0));
1057 }
1058
1059 if(!QRinput::check($mode, $size, $setData)) {
1060 throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
1061 return null;
1062 }
1063
1064 $this->mode = $mode;
1065 $this->size = $size;
1066 $this->data = $setData;
1067 $this->bstream = $bstream;
1068 }
1069
1070 //----------------------------------------------------------------------
1071 public function encodeModeNum($version)
1072 {
1073 try {
1074
1075 $words = (int)($this->size / 3);
1076 $bs = new QRbitstream();
1077
1078 $val = 0x1;
1079 $bs->appendNum(4, $val);
1080 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size);
1081
1082 for($i=0; $i<$words; $i++) {
1083 $val = (ord($this->data[$i*3 ]) - ord('0')) * 100;
1084 $val += (ord($this->data[$i*3+1]) - ord('0')) * 10;
1085 $val += (ord($this->data[$i*3+2]) - ord('0'));
1086 $bs->appendNum(10, $val);
1087 }
1088
1089 if($this->size - $words * 3 == 1) {
1090 $val = ord($this->data[$words*3]) - ord('0');
1091 $bs->appendNum(4, $val);
1092 } else if($this->size - $words * 3 == 2) {
1093 $val = (ord($this->data[$words*3 ]) - ord('0')) * 10;
1094 $val += (ord($this->data[$words*3+1]) - ord('0'));
1095 $bs->appendNum(7, $val);
1096 }
1097
1098 $this->bstream = $bs;
1099 return 0;
1100
1101 } catch (Exception $e) {
1102 return -1;
1103 }
1104 }
1105
1106 //----------------------------------------------------------------------
1107 public function encodeModeAn($version)
1108 {
1109 try {
1110 $words = (int)($this->size / 2);
1111 $bs = new QRbitstream();
1112
1113 $bs->appendNum(4, 0x02);
1114 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size);
1115
1116 for($i=0; $i<$words; $i++) {
1117 $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45;
1118 $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));
1119
1120 $bs->appendNum(11, $val);
1121 }
1122
1123 if($this->size & 1) {
1124 $val = QRinput::lookAnTable(ord($this->data[$words * 2]));
1125 $bs->appendNum(6, $val);
1126 }
1127
1128 $this->bstream = $bs;
1129 return 0;
1130
1131 } catch (Exception $e) {
1132 return -1;
1133 }
1134 }
1135
1136 //----------------------------------------------------------------------
1137 public function encodeMode8($version)
1138 {
1139 try {
1140 $bs = new QRbitstream();
1141
1142 $bs->appendNum(4, 0x4);
1143 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size);
1144
1145 for($i=0; $i<$this->size; $i++) {
1146 $bs->appendNum(8, ord($this->data[$i]));
1147 }
1148
1149 $this->bstream = $bs;
1150 return 0;
1151
1152 } catch (Exception $e) {
1153 return -1;
1154 }
1155 }
1156
1157 //----------------------------------------------------------------------
1158 public function encodeModeKanji($version)
1159 {
1160 try {
1161
1162 $bs = new QRbitrtream();
1163
1164 $bs->appendNum(4, 0x8);
1165 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2));
1166
1167 for($i=0; $i<$this->size; $i+=2) {
1168 $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]);
1169 if($val <= 0x9ffc) {
1170 $val -= 0x8140;
1171 } else {
1172 $val -= 0xc140;
1173 }
1174
1175 $h = ($val >> 8) * 0xc0;
1176 $val = ($val & 0xff) + $h;
1177
1178 $bs->appendNum(13, $val);
1179 }
1180
1181 $this->bstream = $bs;
1182 return 0;
1183
1184 } catch (Exception $e) {
1185 return -1;
1186 }
1187 }
1188
1189 //----------------------------------------------------------------------
1190 public function encodeModeStructure()
1191 {
1192 try {
1193 $bs = new QRbitstream();
1194
1195 $bs->appendNum(4, 0x03);
1196 $bs->appendNum(4, ord($this->data[1]) - 1);
1197 $bs->appendNum(4, ord($this->data[0]) - 1);
1198 $bs->appendNum(8, ord($this->data[2]));
1199
1200 $this->bstream = $bs;
1201 return 0;
1202
1203 } catch (Exception $e) {
1204 return -1;
1205 }
1206 }
1207
1208 //----------------------------------------------------------------------
1209 public function estimateBitStreamSizeOfEntry($version)
1210 {
1211 $bits = 0;
1212
1213 if($version == 0)
1214 $version = 1;
1215
1216 switch($this->mode) {
1217 case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break;
1218 case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break;
1219 case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break;
1220 case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break;
1221 case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS;
1222 default:
1223 return 0;
1224 }
1225
1226 $l = QRspec::lengthIndicator($this->mode, $version);
1227 $m = 1 << $l;
1228 $num = (int)(($this->size + $m - 1) / $m);
1229
1230 $bits += $num * (4 + $l);
1231
1232 return $bits;
1233 }
1234
1235 //----------------------------------------------------------------------
1236 public function encodeBitStream($version)
1237 {
1238 try {
1239
1240 unset($this->bstream);
1241 $words = QRspec::maximumWords($this->mode, $version);
1242
1243 if($this->size > $words) {
1244
1245 $st1 = new QRinputItem($this->mode, $words, $this->data);
1246 $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words));
1247
1248 $st1->encodeBitStream($version);
1249 $st2->encodeBitStream($version);
1250
1251 $this->bstream = new QRbitstream();
1252 $this->bstream->append($st1->bstream);
1253 $this->bstream->append($st2->bstream);
1254
1255 unset($st1);
1256 unset($st2);
1257
1258 } else {
1259
1260 $ret = 0;
1261
1262 switch($this->mode) {
1263 case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break;
1264 case QR_MODE_AN: $ret = $this->encodeModeAn($version); break;
1265 case QR_MODE_8: $ret = $this->encodeMode8($version); break;
1266 case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break;
1267 case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break;
1268
1269 default:
1270 break;
1271 }
1272
1273 if($ret < 0)
1274 return -1;
1275 }
1276
1277 return $this->bstream->size();
1278
1279 } catch (Exception $e) {
1280 return -1;
1281 }
1282 }
1283 };
1284
1285 //##########################################################################
1286
1287 class QRinput {
1288
1289 public $items;
1290
1291 private $version;
1292 private $level;
1293
1294 //----------------------------------------------------------------------
1295 public function __construct($version = 0, $level = QR_ECLEVEL_L)
1296 {
1297 if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {
1298 throw new Exception('Invalid version no');
1299 return NULL;
1300 }
1301
1302 $this->version = $version;
1303 $this->level = $level;
1304 }
1305
1306 //----------------------------------------------------------------------
1307 public function getVersion()
1308 {
1309 return $this->version;
1310 }
1311
1312 //----------------------------------------------------------------------
1313 public function setVersion($version)
1314 {
1315 if($version < 0 || $version > QRSPEC_VERSION_MAX) {
1316 throw new Exception('Invalid version no');
1317 return -1;
1318 }
1319
1320 $this->version = $version;
1321
1322 return 0;
1323 }
1324
1325 //----------------------------------------------------------------------
1326 public function getErrorCorrectionLevel()
1327 {
1328 return $this->level;
1329 }
1330
1331 //----------------------------------------------------------------------
1332 public function setErrorCorrectionLevel($level)
1333 {
1334 if($level > QR_ECLEVEL_H) {
1335 throw new Exception('Invalid ECLEVEL');
1336 return -1;
1337 }
1338
1339 $this->level = $level;
1340
1341 return 0;
1342 }
1343
1344 //----------------------------------------------------------------------
1345 public function appendEntry(QRinputItem $entry)
1346 {
1347 $this->items[] = $entry;
1348 }
1349
1350 //----------------------------------------------------------------------
1351 public function append($mode, $size, $data)
1352 {
1353 try {
1354 $entry = new QRinputItem($mode, $size, $data);
1355 $this->items[] = $entry;
1356 return 0;
1357 } catch (Exception $e) {
1358 return -1;
1359 }
1360 }
1361
1362 //----------------------------------------------------------------------
1363
1364 public function insertStructuredAppendHeader($size, $index, $parity)
1365 {
1366 if( $size > MAX_STRUCTURED_SYMBOLS ) {
1367 throw new Exception('insertStructuredAppendHeader wrong size');
1368 }
1369
1370 if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
1371 throw new Exception('insertStructuredAppendHeader wrong index');
1372 }
1373
1374 $buf = array($size, $index, $parity);
1375
1376 try {
1377 $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);
1378 array_unshift($this->items, $entry);
1379 return 0;
1380 } catch (Exception $e) {
1381 return -1;
1382 }
1383 }
1384
1385 //----------------------------------------------------------------------
1386 public function calcParity()
1387 {
1388 $parity = 0;
1389
1390 foreach($this->items as $item) {
1391 if($item->mode != QR_MODE_STRUCTURE) {
1392 for($i=$item->size-1; $i>=0; $i--) {
1393 $parity ^= $item->data[$i];
1394 }
1395 }
1396 }
1397
1398 return $parity;
1399 }
1400
1401 //----------------------------------------------------------------------
1402 public static function checkModeNum($size, $data)
1403 {
1404 for($i=0; $i<$size; $i++) {
1405 if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){
1406 return false;
1407 }
1408 }
1409
1410 return true;
1411 }
1412
1413 //----------------------------------------------------------------------
1414 public static function estimateBitsModeNum($size)
1415 {
1416 $w = (int)$size / 3;
1417 $bits = $w * 10;
1418
1419 switch($size - $w * 3) {
1420 case 1:
1421 $bits += 4;
1422 break;
1423 case 2:
1424 $bits += 7;
1425 break;
1426 default:
1427 break;
1428 }
1429
1430 return $bits;
1431 }
1432
1433 //----------------------------------------------------------------------
1434 public static $anTable = array(
1435 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1436 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1437 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
1438 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1,
1439 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1440 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
1441 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1442 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1443 );
1444
1445 //----------------------------------------------------------------------
1446 public static function lookAnTable($c)
1447 {
1448 return (($c > 127)?-1:self::$anTable[$c]);
1449 }
1450
1451 //----------------------------------------------------------------------
1452 public static function checkModeAn($size, $data)
1453 {
1454 for($i=0; $i<$size; $i++) {
1455 if (self::lookAnTable(ord($data[$i])) == -1) {
1456 return false;
1457 }
1458 }
1459
1460 return true;
1461 }
1462
1463 //----------------------------------------------------------------------
1464 public static function estimateBitsModeAn($size)
1465 {
1466 $w = (int)($size / 2);
1467 $bits = $w * 11;
1468
1469 if($size & 1) {
1470 $bits += 6;
1471 }
1472
1473 return $bits;
1474 }
1475
1476 //----------------------------------------------------------------------
1477 public static function estimateBitsMode8($size)
1478 {
1479 return $size * 8;
1480 }
1481
1482 //----------------------------------------------------------------------
1483 public function estimateBitsModeKanji($size)
1484 {
1485 return (int)(($size / 2) * 13);
1486 }
1487
1488 //----------------------------------------------------------------------
1489 public static function checkModeKanji($size, $data)
1490 {
1491 if($size & 1)
1492 return false;
1493
1494 for($i=0; $i<$size; $i+=2) {
1495 $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
1496 if( $val < 0x8140
1497 || ($val > 0x9ffc && $val < 0xe040)
1498 || $val > 0xebbf) {
1499 return false;
1500 }
1501 }
1502
1503 return true;
1504 }
1505
1506 /***********************************************************************
1507 * Validation
1508 **********************************************************************/
1509
1510 public static function check($mode, $size, $data)
1511 {
1512 if($size <= 0)
1513 return false;
1514
1515 switch($mode) {
1516 case QR_MODE_NUM: return self::checkModeNum($size, $data); break;
1517 case QR_MODE_AN: return self::checkModeAn($size, $data); break;
1518 case QR_MODE_KANJI: return self::checkModeKanji($size, $data); break;
1519 case QR_MODE_8: return true; break;
1520 case QR_MODE_STRUCTURE: return true; break;
1521
1522 default:
1523 break;
1524 }
1525
1526 return false;
1527 }
1528
1529
1530 //----------------------------------------------------------------------
1531 public function estimateBitStreamSize($version)
1532 {
1533 $bits = 0;
1534
1535 foreach($this->items as $item) {
1536 $bits += $item->estimateBitStreamSizeOfEntry($version);
1537 }
1538
1539 return $bits;
1540 }
1541
1542 //----------------------------------------------------------------------
1543 public function estimateVersion()
1544 {
1545 $version = 0;
1546 $prev = 0;
1547 do {
1548 $prev = $version;
1549 $bits = $this->estimateBitStreamSize($prev);
1550 $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1551 if ($version < 0) {
1552 return -1;
1553 }
1554 } while ($version > $prev);
1555
1556 return $version;
1557 }
1558
1559 //----------------------------------------------------------------------
1560 public static function lengthOfCode($mode, $version, $bits)
1561 {
1562 $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);
1563 switch($mode) {
1564 case QR_MODE_NUM:
1565 $chunks = (int)($payload / 10);
1566 $remain = $payload - $chunks * 10;
1567 $size = $chunks * 3;
1568 if($remain >= 7) {
1569 $size += 2;
1570 } else if($remain >= 4) {
1571 $size += 1;
1572 }
1573 break;
1574 case QR_MODE_AN:
1575 $chunks = (int)($payload / 11);
1576 $remain = $payload - $chunks * 11;
1577 $size = $chunks * 2;
1578 if($remain >= 6)
1579 $size++;
1580 break;
1581 case QR_MODE_8:
1582 $size = (int)($payload / 8);
1583 break;
1584 case QR_MODE_KANJI:
1585 $size = (int)(($payload / 13) * 2);
1586 break;
1587 case QR_MODE_STRUCTURE:
1588 $size = (int)($payload / 8);
1589 break;
1590 default:
1591 $size = 0;
1592 break;
1593 }
1594
1595 $maxsize = QRspec::maximumWords($mode, $version);
1596 if($size < 0) $size = 0;
1597 if($size > $maxsize) $size = $maxsize;
1598
1599 return $size;
1600 }
1601
1602 //----------------------------------------------------------------------
1603 public function createBitStream()
1604 {
1605 $total = 0;
1606
1607 foreach($this->items as $item) {
1608 $bits = $item->encodeBitStream($this->version);
1609
1610 if($bits < 0)
1611 return -1;
1612
1613 $total += $bits;
1614 }
1615
1616 return $total;
1617 }
1618
1619 //----------------------------------------------------------------------
1620 public function convertData()
1621 {
1622 $ver = $this->estimateVersion();
1623 if($ver > $this->getVersion()) {
1624 $this->setVersion($ver);
1625 }
1626
1627 for(;;) {
1628 $bits = $this->createBitStream();
1629
1630 if($bits < 0)
1631 return -1;
1632
1633 $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1634 if($ver < 0) {
1635 throw new Exception('WRONG VERSION');
1636 return -1;
1637 } else if($ver > $this->getVersion()) {
1638 $this->setVersion($ver);
1639 } else {
1640 break;
1641 }
1642 }
1643
1644 return 0;
1645 }
1646
1647 //----------------------------------------------------------------------
1648 public function appendPaddingBit(&$bstream)
1649 {
1650 $bits = $bstream->size();
1651 $maxwords = QRspec::getDataLength($this->version, $this->level);
1652 $maxbits = $maxwords * 8;
1653
1654 if ($maxbits == $bits) {
1655 return 0;
1656 }
1657
1658 if ($maxbits - $bits < 5) {
1659 return $bstream->appendNum($maxbits - $bits, 0);
1660 }
1661
1662 $bits += 4;
1663 $words = (int)(($bits + 7) / 8);
1664
1665 $padding = new QRbitstream();
1666 $ret = $padding->appendNum($words * 8 - $bits + 4, 0);
1667
1668 if($ret < 0)
1669 return $ret;
1670
1671 $padlen = $maxwords - $words;
1672
1673 if($padlen > 0) {
1674
1675 $padbuf = array();
1676 for($i=0; $i<$padlen; $i++) {
1677 $padbuf[$i] = ($i&1)?0x11:0xec;
1678 }
1679
1680 $ret = $padding->appendBytes($padlen, $padbuf);
1681
1682 if($ret < 0)
1683 return $ret;
1684
1685 }
1686
1687 $ret = $bstream->append($padding);
1688
1689 return $ret;
1690 }
1691
1692 //----------------------------------------------------------------------
1693 public function mergeBitStream()
1694 {
1695 if($this->convertData() < 0) {
1696 return null;
1697 }
1698
1699 $bstream = new QRbitstream();
1700
1701 foreach($this->items as $item) {
1702 $ret = $bstream->append($item->bstream);
1703 if($ret < 0) {
1704 return null;
1705 }
1706 }
1707
1708 return $bstream;
1709 }
1710
1711 //----------------------------------------------------------------------
1712 public function getBitStream()
1713 {
1714
1715 $bstream = $this->mergeBitStream();
1716
1717 if($bstream == null) {
1718 return null;
1719 }
1720
1721 $ret = $this->appendPaddingBit($bstream);
1722 if($ret < 0) {
1723 return null;
1724 }
1725
1726 return $bstream;
1727 }
1728
1729 //----------------------------------------------------------------------
1730 public function getByteStream()
1731 {
1732 $bstream = $this->getBitStream();
1733 if($bstream == null) {
1734 return null;
1735 }
1736
1737 return $bstream->toByte();
1738 }
1739 }
1740
1741
1742
1743
1744
1745
1746 //---- qrbitstream.php -----------------------------
1747
1748
1749
1750
1751 /*
1752 * PHP QR Code encoder
1753 *
1754 * Bitstream class
1755 *
1756 * Based on libqrencode C library distributed under LGPL 2.1
1757 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
1758 *
1759 * PHP QR Code is distributed under LGPL 3
1760 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
1761 *
1762 * This library is free software; you can redistribute it and/or
1763 * modify it under the terms of the GNU Lesser General Public
1764 * License as published by the Free Software Foundation; either
1765 * version 3 of the License, or any later version.
1766 *
1767 * This library is distributed in the hope that it will be useful,
1768 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1769 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1770 * Lesser General Public License for more details.
1771 *
1772 * You should have received a copy of the GNU Lesser General Public
1773 * License along with this library; if not, write to the Free Software
1774 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1775 */
1776
1777 class QRbitstream {
1778
1779 public $data = array();
1780
1781 //----------------------------------------------------------------------
1782 public function size()
1783 {
1784 return count($this->data);
1785 }
1786
1787 //----------------------------------------------------------------------
1788 public function allocate($setLength)
1789 {
1790 $this->data = array_fill(0, $setLength, 0);
1791 return 0;
1792 }
1793
1794 //----------------------------------------------------------------------
1795 public static function newFromNum($bits, $num)
1796 {
1797 $bstream = new QRbitstream();
1798 $bstream->allocate($bits);
1799
1800 $mask = 1 << ($bits - 1);
1801 for($i=0; $i<$bits; $i++) {
1802 if($num & $mask) {
1803 $bstream->data[$i] = 1;
1804 } else {
1805 $bstream->data[$i] = 0;
1806 }
1807 $mask = $mask >> 1;
1808 }
1809
1810 return $bstream;
1811 }
1812
1813 //----------------------------------------------------------------------
1814 public static function newFromBytes($size, $data)
1815 {
1816 $bstream = new QRbitstream();
1817 $bstream->allocate($size * 8);
1818 $p=0;
1819
1820 for($i=0; $i<$size; $i++) {
1821 $mask = 0x80;
1822 for($j=0; $j<8; $j++) {
1823 if($data[$i] & $mask) {
1824 $bstream->data[$p] = 1;
1825 } else {
1826 $bstream->data[$p] = 0;
1827 }
1828 $p++;
1829 $mask = $mask >> 1;
1830 }
1831 }
1832
1833 return $bstream;
1834 }
1835
1836 //----------------------------------------------------------------------
1837 public function append(QRbitstream $arg)
1838 {
1839 if (is_null($arg)) {
1840 return -1;
1841 }
1842
1843 if($arg->size() == 0) {
1844 return 0;
1845 }
1846
1847 if($this->size() == 0) {
1848 $this->data = $arg->data;
1849 return 0;
1850 }
1851
1852 $this->data = array_values(array_merge($this->data, $arg->data));
1853
1854 return 0;
1855 }
1856
1857 //----------------------------------------------------------------------
1858 public function appendNum($bits, $num)
1859 {
1860 if ($bits == 0)
1861 return 0;
1862
1863 $b = QRbitstream::newFromNum($bits, $num);
1864
1865 if(is_null($b))
1866 return -1;
1867
1868 $ret = $this->append($b);
1869 unset($b);
1870
1871 return $ret;
1872 }
1873
1874 //----------------------------------------------------------------------
1875 public function appendBytes($size, $data)
1876 {
1877 if ($size == 0)
1878 return 0;
1879
1880 $b = QRbitstream::newFromBytes($size, $data);
1881
1882 if(is_null($b))
1883 return -1;
1884
1885 $ret = $this->append($b);
1886 unset($b);
1887
1888 return $ret;
1889 }
1890
1891 //----------------------------------------------------------------------
1892 public function toByte()
1893 {
1894
1895 $size = $this->size();
1896
1897 if($size == 0) {
1898 return array();
1899 }
1900
1901 $data = array_fill(0, (int)(($size + 7) / 8), 0);
1902 $bytes = (int)($size / 8);
1903
1904 $p = 0;
1905
1906 for($i=0; $i<$bytes; $i++) {
1907 $v = 0;
1908 for($j=0; $j<8; $j++) {
1909 $v = $v << 1;
1910 $v |= $this->data[$p];
1911 $p++;
1912 }
1913 $data[$i] = $v;
1914 }
1915
1916 if($size & 7) {
1917 $v = 0;
1918 for($j=0; $j<($size & 7); $j++) {
1919 $v = $v << 1;
1920 $v |= $this->data[$p];
1921 $p++;
1922 }
1923 $data[$bytes] = $v;
1924 }
1925
1926 return $data;
1927 }
1928
1929 }
1930
1931
1932
1933
1934 //---- qrsplit.php -----------------------------
1935
1936
1937
1938
1939 /*
1940 * PHP QR Code encoder
1941 *
1942 * Input splitting classes
1943 *
1944 * Based on libqrencode C library distributed under LGPL 2.1
1945 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
1946 *
1947 * PHP QR Code is distributed under LGPL 3
1948 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
1949 *
1950 * The following data / specifications are taken from
1951 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
1952 * or
1953 * "Automatic identification and data capture techniques --
1954 * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
1955 *
1956 * This library is free software; you can redistribute it and/or
1957 * modify it under the terms of the GNU Lesser General Public
1958 * License as published by the Free Software Foundation; either
1959 * version 3 of the License, or any later version.
1960 *
1961 * This library is distributed in the hope that it will be useful,
1962 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1963 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1964 * Lesser General Public License for more details.
1965 *
1966 * You should have received a copy of the GNU Lesser General Public
1967 * License along with this library; if not, write to the Free Software
1968 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1969 */
1970 class QRsplit {
1971
1972 public $dataStr = '';
1973 public $input;
1974 public $modeHint;
1975
1976 //----------------------------------------------------------------------
1977 public function __construct($dataStr, $input, $modeHint)
1978 {
1979 $this->dataStr = $dataStr;
1980 $this->input = $input;
1981 $this->modeHint = $modeHint;
1982 }
1983
1984 //----------------------------------------------------------------------
1985 public static function isdigitat($str, $pos)
1986 {
1987 if ($pos >= strlen($str))
1988 return false;
1989
1990 return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
1991 }
1992
1993 //----------------------------------------------------------------------
1994 public static function isalnumat($str, $pos)
1995 {
1996 if ($pos >= strlen($str))
1997 return false;
1998
1999 return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
2000 }
2001
2002 //----------------------------------------------------------------------
2003 public function identifyMode($pos)
2004 {
2005 if ($pos >= strlen($this->dataStr))
2006 return QR_MODE_NUL;
2007
2008 $c = $this->dataStr[$pos];
2009
2010 if(self::isdigitat($this->dataStr, $pos)) {
2011 return QR_MODE_NUM;
2012 } else if(self::isalnumat($this->dataStr, $pos)) {
2013 return QR_MODE_AN;
2014 } else if($this->modeHint == QR_MODE_KANJI) {
2015
2016 if ($pos+1 < strlen($this->dataStr))
2017 {
2018 $d = $this->dataStr[$pos+1];
2019 $word = (ord($c) << 8) | ord($d);
2020 if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
2021 return QR_MODE_KANJI;
2022 }
2023 }
2024 }
2025
2026 return QR_MODE_8;
2027 }
2028
2029 //----------------------------------------------------------------------
2030 public function eatNum()
2031 {
2032 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
2033
2034 $p = 0;
2035 while(self::isdigitat($this->dataStr, $p)) {
2036 $p++;
2037 }
2038
2039 $run = $p;
2040 $mode = $this->identifyMode($p);
2041
2042 if($mode == QR_MODE_8) {
2043 $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
2044 + QRinput::estimateBitsMode8(1) // + 4 + l8
2045 - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
2046 if($dif > 0) {
2047 return $this->eat8();
2048 }
2049 }
2050 if($mode == QR_MODE_AN) {
2051 $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
2052 + QRinput::estimateBitsModeAn(1) // + 4 + la
2053 - QRinput::estimateBitsModeAn($run + 1);// - 4 - la
2054 if($dif > 0) {
2055 return $this->eatAn();
2056 }
2057 }
2058
2059 $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
2060 if($ret < 0)
2061 return -1;
2062
2063 return $run;
2064 }
2065
2066 //----------------------------------------------------------------------
2067 public function eatAn()
2068 {
2069 $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
2070 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
2071
2072 $p = 0;
2073
2074 while(self::isalnumat($this->dataStr, $p)) {
2075 if(self::isdigitat($this->dataStr, $p)) {
2076 $q = $p;
2077 while(self::isdigitat($this->dataStr, $q)) {
2078 $q++;
2079 }
2080
2081 $dif = QRinput::estimateBitsModeAn($p) // + 4 + la
2082 + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
2083 - QRinput::estimateBitsModeAn($q); // - 4 - la
2084
2085 if($dif < 0) {
2086 break;
2087 } else {
2088 $p = $q;
2089 }
2090 } else {
2091 $p++;
2092 }
2093 }
2094
2095 $run = $p;
2096
2097 if(!self::isalnumat($this->dataStr, $p)) {
2098 $dif = QRinput::estimateBitsModeAn($run) + 4 + $la
2099 + QRinput::estimateBitsMode8(1) // + 4 + l8
2100 - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
2101 if($dif > 0) {
2102 return $this->eat8();
2103 }
2104 }
2105
2106 $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
2107 if($ret < 0)
2108 return -1;
2109
2110 return $run;
2111 }
2112
2113 //----------------------------------------------------------------------
2114 public function eatKanji()
2115 {
2116 $p = 0;
2117
2118 while($this->identifyMode($p) == QR_MODE_KANJI) {
2119 $p += 2;
2120 }
2121
2122 $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
2123 if($ret < 0)
2124 return -1;
2125
2126 return $run;
2127 }
2128
2129 //----------------------------------------------------------------------
2130 public function eat8()
2131 {
2132 $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
2133 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
2134
2135 $p = 1;
2136 $dataStrLen = strlen($this->dataStr);
2137
2138 while($p < $dataStrLen) {
2139
2140 $mode = $this->identifyMode($p);
2141 if($mode == QR_MODE_KANJI) {
2142 break;
2143 }
2144 if($mode == QR_MODE_NUM) {
2145 $q = $p;
2146 while(self::isdigitat($this->dataStr, $q)) {
2147 $q++;
2148 }
2149 $dif = QRinput::estimateBitsMode8($p) // + 4 + l8
2150 + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
2151 - QRinput::estimateBitsMode8($q); // - 4 - l8
2152 if($dif < 0) {
2153 break;
2154 } else {
2155 $p = $q;
2156 }
2157 } else if($mode == QR_MODE_AN) {
2158 $q = $p;
2159 while(self::isalnumat($this->dataStr, $q)) {
2160 $q++;
2161 }
2162 $dif = QRinput::estimateBitsMode8($p) // + 4 + l8
2163 + QRinput::estimateBitsModeAn($q - $p) + 4 + $la
2164 - QRinput::estimateBitsMode8($q); // - 4 - l8
2165 if($dif < 0) {
2166 break;
2167 } else {
2168 $p = $q;
2169 }
2170 } else {
2171 $p++;
2172 }
2173 }
2174
2175 $run = $p;
2176 $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
2177
2178 if($ret < 0)
2179 return -1;
2180
2181 return $run;
2182 }
2183
2184 //----------------------------------------------------------------------
2185 public function splitString()
2186 {
2187 while (strlen($this->dataStr) > 0)
2188 {
2189 if($this->dataStr == '')
2190 return 0;
2191
2192 $mode = $this->identifyMode(0);
2193
2194 switch ($mode) {
2195 case QR_MODE_NUM: $length = $this->eatNum(); break;
2196 case QR_MODE_AN: $length = $this->eatAn(); break;
2197 case QR_MODE_KANJI:
2198 if ($this->modeHint == QR_MODE_KANJI)
2199 $length = $this->eatKanji();
2200 else $length = $this->eat8();
2201 break;
2202 default: $length = $this->eat8(); break;
2203
2204 }
2205
2206 if($length == 0) return 0;
2207 if($length < 0) return -1;
2208
2209 $this->dataStr = substr($this->dataStr, $length);
2210 }
2211 }
2212
2213 //----------------------------------------------------------------------
2214 public function toUpper()
2215 {
2216 $stringLen = strlen($this->dataStr);
2217 $p = 0;
2218
2219 while ($p<$stringLen) {
2220 $mode = self::identifyMode(substr($this->dataStr, $p));
2221 if($mode == QR_MODE_KANJI) {
2222 $p += 2;
2223 } else {
2224 if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {
2225 $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
2226 }
2227 $p++;
2228 }
2229 }
2230
2231 return $this->dataStr;
2232 }
2233
2234 //----------------------------------------------------------------------
2235 public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
2236 {
2237 if(is_null($string) || $string == '\0' || $string == '') {
2238 throw new Exception('empty string!!!');
2239 }
2240
2241 $split = new QRsplit($string, $input, $modeHint);
2242
2243 if(!$casesensitive)
2244 $split->toUpper();
2245
2246 return $split->splitString();
2247 }
2248 }
2249
2250
2251
2252 //---- qrrscode.php -----------------------------
2253
2254
2255
2256
2257 /*
2258 * PHP QR Code encoder
2259 *
2260 * Reed-Solomon error correction support
2261 *
2262 * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
2263 * (libfec is released under the GNU Lesser General Public License.)
2264 *
2265 * Based on libqrencode C library distributed under LGPL 2.1
2266 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
2267 *
2268 * PHP QR Code is distributed under LGPL 3
2269 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
2270 *
2271 * This library is free software; you can redistribute it and/or
2272 * modify it under the terms of the GNU Lesser General Public
2273 * License as published by the Free Software Foundation; either
2274 * version 3 of the License, or any later version.
2275 *
2276 * This library is distributed in the hope that it will be useful,
2277 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2278 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2279 * Lesser General Public License for more details.
2280 *
2281 * You should have received a copy of the GNU Lesser General Public
2282 * License along with this library; if not, write to the Free Software
2283 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2284 */
2285
2286 class QRrsItem {
2287
2288 public $mm; // Bits per symbol
2289 public $nn; // Symbols per block (= (1<<mm)-1)
2290 public $alpha_to = array(); // log lookup table
2291 public $index_of = array(); // Antilog lookup table
2292 public $genpoly = array(); // Generator polynomial
2293 public $nroots; // Number of generator roots = number of parity symbols
2294 public $fcr; // First consecutive root, index form
2295 public $prim; // Primitive element, index form
2296 public $iprim; // prim-th root of 1, index form
2297 public $pad; // Padding bytes in shortened block
2298 public $gfpoly;
2299
2300 //----------------------------------------------------------------------
2301 public function modnn($x)
2302 {
2303 while ($x >= $this->nn) {
2304 $x -= $this->nn;
2305 $x = ($x >> $this->mm) + ($x & $this->nn);
2306 }
2307
2308 return $x;
2309 }
2310
2311 //----------------------------------------------------------------------
2312 public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
2313 {
2314 // Common code for intializing a Reed-Solomon control block (char or int symbols)
2315 // Copyright 2004 Phil Karn, KA9Q
2316 // May be used under the terms of the GNU Lesser General Public License (LGPL)
2317
2318 $rs = null;
2319
2320 // Check parameter ranges
2321 if($symsize < 0 || $symsize > 8) return $rs;
2322 if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs;
2323 if($prim <= 0 || $prim >= (1<<$symsize)) return $rs;
2324 if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values!
2325 if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding
2326
2327 $rs = new QRrsItem();
2328 $rs->mm = $symsize;
2329 $rs->nn = (1<<$symsize)-1;
2330 $rs->pad = $pad;
2331
2332 $rs->alpha_to = array_fill(0, $rs->nn+1, 0);
2333 $rs->index_of = array_fill(0, $rs->nn+1, 0);
2334
2335 // PHP style macro replacement ;)
2336 $NN =& $rs->nn;
2337 $A0 =& $NN;
2338
2339 // Generate Galois field lookup tables
2340 $rs->index_of[0] = $A0; // log(zero) = -inf
2341 $rs->alpha_to[$A0] = 0; // alpha**-inf = 0
2342 $sr = 1;
2343
2344 for($i=0; $i<$rs->nn; $i++) {
2345 $rs->index_of[$sr] = $i;
2346 $rs->alpha_to[$i] = $sr;
2347 $sr <<= 1;
2348 if($sr & (1<<$symsize)) {
2349 $sr ^= $gfpoly;
2350 }
2351 $sr &= $rs->nn;
2352 }
2353
2354 if($sr != 1){
2355 // field generator polynomial is not primitive!
2356 $rs = NULL;
2357 return $rs;
2358 }
2359
2360 /* Form RS code generator polynomial from its roots */
2361 $rs->genpoly = array_fill(0, $nroots+1, 0);
2362
2363 $rs->fcr = $fcr;
2364 $rs->prim = $prim;
2365 $rs->nroots = $nroots;
2366 $rs->gfpoly = $gfpoly;
2367
2368 /* Find prim-th root of 1, used in decoding */
2369 for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn)
2370 ; // intentional empty-body loop!
2371
2372 $rs->iprim = (int)($iprim / $prim);
2373 $rs->genpoly[0] = 1;
2374
2375 for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
2376 $rs->genpoly[$i+1] = 1;
2377
2378 // Multiply rs->genpoly[] by @**(root + x)
2379 for ($j = $i; $j > 0; $j--) {
2380 if ($rs->genpoly[$j] != 0) {
2381 $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];
2382 } else {
2383 $rs->genpoly[$j] = $rs->genpoly[$j-1];
2384 }
2385 }
2386 // rs->genpoly[0] can never be zero
2387 $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];
2388 }
2389
2390 // convert rs->genpoly[] to index form for quicker encoding
2391 for ($i = 0; $i <= $nroots; $i++)
2392 $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
2393
2394 return $rs;
2395 }
2396
2397 //----------------------------------------------------------------------
2398 public function encode_rs_char($data, &$parity)
2399 {
2400 $MM =& $this->mm;
2401 $NN =& $this->nn;
2402 $ALPHA_TO =& $this->alpha_to;
2403 $INDEX_OF =& $this->index_of;
2404 $GENPOLY =& $this->genpoly;
2405 $NROOTS =& $this->nroots;
2406 $FCR =& $this->fcr;
2407 $PRIM =& $this->prim;
2408 $IPRIM =& $this->iprim;
2409 $PAD =& $this->pad;
2410 $A0 =& $NN;
2411
2412 $parity = array_fill(0, $NROOTS, 0);
2413
2414 for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) {
2415
2416 $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2417 if($feedback != $A0) {
2418 // feedback term is non-zero
2419
2420 // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2421 // always be for the polynomials constructed by init_rs()
2422 $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);
2423
2424 for($j=1;$j<$NROOTS;$j++) {
2425 $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])];
2426 }
2427 }
2428
2429 // Shift
2430 array_shift($parity);
2431 if($feedback != $A0) {
2432 array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);
2433 } else {
2434 array_push($parity, 0);
2435 }
2436 }
2437 }
2438 }
2439
2440 //##########################################################################
2441
2442 class QRrs {
2443
2444 public static $items = array();
2445
2446 //----------------------------------------------------------------------
2447 public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
2448 {
2449 foreach(self::$items as $rs) {
2450 if($rs->pad != $pad) continue;
2451 if($rs->nroots != $nroots) continue;
2452 if($rs->mm != $symsize) continue;
2453 if($rs->gfpoly != $gfpoly) continue;
2454 if($rs->fcr != $fcr) continue;
2455 if($rs->prim != $prim) continue;
2456
2457 return $rs;
2458 }
2459
2460 $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2461 array_unshift(self::$items, $rs);
2462
2463 return $rs;
2464 }
2465 }
2466
2467
2468
2469 //---- qrmask.php -----------------------------
2470
2471
2472
2473
2474 /*
2475 * PHP QR Code encoder
2476 *
2477 * Masking
2478 *
2479 * Based on libqrencode C library distributed under LGPL 2.1
2480 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
2481 *
2482 * PHP QR Code is distributed under LGPL 3
2483 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
2484 *
2485 * This library is free software; you can redistribute it and/or
2486 * modify it under the terms of the GNU Lesser General Public
2487 * License as published by the Free Software Foundation; either
2488 * version 3 of the License, or any later version.
2489 *
2490 * This library is distributed in the hope that it will be useful,
2491 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2492 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2493 * Lesser General Public License for more details.
2494 *
2495 * You should have received a copy of the GNU Lesser General Public
2496 * License along with this library; if not, write to the Free Software
2497 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2498 */
2499
2500 define('N1', 3);
2501 define('N2', 3);
2502 define('N3', 40);
2503 define('N4', 10);
2504
2505 class QRmask {
2506
2507 public $runLength = array();
2508
2509 //----------------------------------------------------------------------
2510 public function __construct()
2511 {
2512 $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
2513 }
2514
2515 //----------------------------------------------------------------------
2516 public function writeFormatInformation($width, &$frame, $mask, $level)
2517 {
2518 $blacks = 0;
2519 $format = QRspec::getFormatInfo($mask, $level);
2520
2521 for($i=0; $i<8; $i++) {
2522 if($format & 1) {
2523 $blacks += 2;
2524 $v = 0x85;
2525 } else {
2526 $v = 0x84;
2527 }
2528
2529 $frame[8][$width - 1 - $i] = chr($v);
2530 if($i < 6) {
2531 $frame[$i][8] = chr($v);
2532 } else {
2533 $frame[$i + 1][8] = chr($v);
2534 }
2535 $format = $format >> 1;
2536 }
2537
2538 for($i=0; $i<7; $i++) {
2539 if($format & 1) {
2540 $blacks += 2;
2541 $v = 0x85;
2542 } else {
2543 $v = 0x84;
2544 }
2545
2546 $frame[$width - 7 + $i][8] = chr($v);
2547 if($i == 0) {
2548 $frame[8][7] = chr($v);
2549 } else {
2550 $frame[8][6 - $i] = chr($v);
2551 }
2552
2553 $format = $format >> 1;
2554 }
2555
2556 return $blacks;
2557 }
2558
2559 //----------------------------------------------------------------------
2560 public function mask0($x, $y) { return ($x+$y)&1; }
2561 public function mask1($x, $y) { return ($y&1); }
2562 public function mask2($x, $y) { return ($x%3); }
2563 public function mask3($x, $y) { return ($x+$y)%3; }
2564 public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }
2565 public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; }
2566 public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; }
2567 public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; }
2568
2569 //----------------------------------------------------------------------
2570 private function generateMaskNo($maskNo, $width, $frame)
2571 {
2572 $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
2573
2574 for($y=0; $y<$width; $y++) {
2575 for($x=0; $x<$width; $x++) {
2576 if(ord($frame[$y][$x]) & 0x80) {
2577 $bitMask[$y][$x] = 0;
2578 } else {
2579 $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
2580 $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
2581 }
2582
2583 }
2584 }
2585
2586 return $bitMask;
2587 }
2588
2589 //----------------------------------------------------------------------
2590 public static function serial($bitFrame)
2591 {
2592 $codeArr = array();
2593
2594 foreach ($bitFrame as $line)
2595 $codeArr[] = join('', $line);
2596
2597 return gzcompress(join("\n", $codeArr), 9);
2598 }
2599
2600 //----------------------------------------------------------------------
2601 public static function unserial($code)
2602 {
2603 $codeArr = array();
2604
2605 $codeLines = explode("\n", gzuncompress($code));
2606 foreach ($codeLines as $line)
2607 $codeArr[] = str_split($line);
2608
2609 return $codeArr;
2610 }
2611
2612 //----------------------------------------------------------------------
2613 public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false)
2614 {
2615 $b = 0;
2616 $bitMask = array();
2617
2618 $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
2619
2620 if (QR_CACHEABLE) {
2621 if (file_exists($fileName)) {
2622 $bitMask = self::unserial(file_get_contents($fileName));
2623 } else {
2624 $bitMask = $this->generateMaskNo($maskNo, $width, $s);
2625 if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
2626 mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
2627 file_put_contents($fileName, self::serial($bitMask));
2628 }
2629 } else {
2630 $bitMask = $this->generateMaskNo($maskNo, $width, $s);
2631 }
2632
2633 if ($maskGenOnly)
2634 return;
2635
2636 $d = $s;
2637
2638 for($y=0; $y<$width; $y++) {
2639 for($x=0; $x<$width; $x++) {
2640 if($bitMask[$y][$x] == 1) {
2641 $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
2642 }
2643 $b += (int)(ord($d[$y][$x]) & 1);
2644 }
2645 }
2646
2647 return $b;
2648 }
2649
2650 //----------------------------------------------------------------------
2651 public function makeMask($width, $frame, $maskNo, $level)
2652 {
2653 $masked = array_fill(0, $width, str_repeat("\0", $width));
2654 $this->makeMaskNo($maskNo, $width, $frame, $masked);
2655 $this->writeFormatInformation($width, $masked, $maskNo, $level);
2656
2657 return $masked;
2658 }
2659
2660 //----------------------------------------------------------------------
2661 public function calcN1N3($length)
2662 {
2663 $demerit = 0;
2664
2665 for($i=0; $i<$length; $i++) {
2666
2667 if($this->runLength[$i] >= 5) {
2668 $demerit += (N1 + ($this->runLength[$i] - 5));
2669 }
2670 if($i & 1) {
2671 if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {
2672 $fact = (int)($this->runLength[$i] / 3);
2673 if(($this->runLength[$i-2] == $fact) &&
2674 ($this->runLength[$i-1] == $fact) &&
2675 ($this->runLength[$i+1] == $fact) &&
2676 ($this->runLength[$i+2] == $fact)) {
2677 if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {
2678 $demerit += N3;
2679 } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {
2680 $demerit += N3;
2681 }
2682 }
2683 }
2684 }
2685 }
2686 return $demerit;
2687 }
2688
2689 //----------------------------------------------------------------------
2690 public function evaluateSymbol($width, $frame)
2691 {
2692 $head = 0;
2693 $demerit = 0;
2694
2695 for($y=0; $y<$width; $y++) {
2696 $head = 0;
2697 $this->runLength[0] = 1;
2698
2699 $frameY = $frame[$y];
2700
2701 if ($y>0)
2702 $frameYM = $frame[$y-1];
2703
2704 for($x=0; $x<$width; $x++) {
2705 if(($x > 0) && ($y > 0)) {
2706 $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
2707 $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
2708
2709 if(($b22 | ($w22 ^ 1))&1) {
2710 $demerit += N2;
2711 }
2712 }
2713 if(($x == 0) && (ord($frameY[$x]) & 1)) {
2714 $this->runLength[0] = -1;
2715 $head = 1;
2716 $this->runLength[$head] = 1;
2717 } else if($x > 0) {
2718 if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
2719 $head++;
2720 $this->runLength[$head] = 1;
2721 } else {
2722 $this->runLength[$head]++;
2723 }
2724 }
2725 }
2726
2727 $demerit += $this->calcN1N3($head+1);
2728 }
2729
2730 for($x=0; $x<$width; $x++) {
2731 $head = 0;
2732 $this->runLength[0] = 1;
2733
2734 for($y=0; $y<$width; $y++) {
2735 if($y == 0 && (ord($frame[$y][$x]) & 1)) {
2736 $this->runLength[0] = -1;
2737 $head = 1;
2738 $this->runLength[$head] = 1;
2739 } else if($y > 0) {
2740 if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
2741 $head++;
2742 $this->runLength[$head] = 1;
2743 } else {
2744 $this->runLength[$head]++;
2745 }
2746 }
2747 }
2748
2749 $demerit += $this->calcN1N3($head+1);
2750 }
2751
2752 return $demerit;
2753 }
2754
2755
2756 //----------------------------------------------------------------------
2757 public function mask($width, $frame, $level)
2758 {
2759 $minDemerit = PHP_INT_MAX;
2760 $bestMaskNum = 0;
2761 $bestMask = array();
2762
2763 $checked_masks = array(0,1,2,3,4,5,6,7);
2764
2765 if (QR_FIND_FROM_RANDOM !== false) {
2766
2767 $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);
2768 for ($i = 0; $i < $howManuOut; $i++) {
2769 $remPos = rand (0, count($checked_masks)-1);
2770 unset($checked_masks[$remPos]);
2771 $checked_masks = array_values($checked_masks);
2772 }
2773
2774 }
2775
2776 $bestMask = $frame;
2777
2778 foreach($checked_masks as $i) {
2779 $mask = array_fill(0, $width, str_repeat("\0", $width));
2780
2781 $demerit = 0;
2782 $blacks = 0;
2783 $blacks = $this->makeMaskNo($i, $width, $frame, $mask);
2784 $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
2785 $blacks = (int)(100 * $blacks / ($width * $width));
2786 $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
2787 $demerit += $this->evaluateSymbol($width, $mask);
2788
2789 if($demerit < $minDemerit) {
2790 $minDemerit = $demerit;
2791 $bestMask = $mask;
2792 $bestMaskNum = $i;
2793 }
2794 }
2795
2796 return $bestMask;
2797 }
2798
2799 //----------------------------------------------------------------------
2800 }
2801
2802
2803
2804
2805 //---- qrencode.php -----------------------------
2806
2807
2808
2809
2810 /*
2811 * PHP QR Code encoder
2812 *
2813 * Main encoder classes.
2814 *
2815 * Based on libqrencode C library distributed under LGPL 2.1
2816 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
2817 *
2818 * PHP QR Code is distributed under LGPL 3
2819 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
2820 *
2821 * This library is free software; you can redistribute it and/or
2822 * modify it under the terms of the GNU Lesser General Public
2823 * License as published by the Free Software Foundation; either
2824 * version 3 of the License, or any later version.
2825 *
2826 * This library is distributed in the hope that it will be useful,
2827 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2828 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2829 * Lesser General Public License for more details.
2830 *
2831 * You should have received a copy of the GNU Lesser General Public
2832 * License along with this library; if not, write to the Free Software
2833 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2834 */
2835
2836 class QRrsblock {
2837 public $dataLength;
2838 public $data = array();
2839 public $eccLength;
2840 public $ecc = array();
2841
2842 public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
2843 {
2844 $rs->encode_rs_char($data, $ecc);
2845
2846 $this->dataLength = $dl;
2847 $this->data = $data;
2848 $this->eccLength = $el;
2849 $this->ecc = $ecc;
2850 }
2851 };
2852
2853 //##########################################################################
2854
2855 class QRrawcode {
2856 public $version;
2857 public $datacode = array();
2858 public $ecccode = array();
2859 public $blocks;
2860 public $rsblocks = array(); //of RSblock
2861 public $count;
2862 public $dataLength;
2863 public $eccLength;
2864 public $b1;
2865
2866 //----------------------------------------------------------------------
2867 public function __construct(QRinput $input)
2868 {
2869 $spec = array(0,0,0,0,0);
2870
2871 $this->datacode = $input->getByteStream();
2872 if(is_null($this->datacode)) {
2873 throw new Exception('null imput string');
2874 }
2875
2876 QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
2877
2878 $this->version = $input->getVersion();
2879 $this->b1 = QRspec::rsBlockNum1($spec);
2880 $this->dataLength = QRspec::rsDataLength($spec);
2881 $this->eccLength = QRspec::rsEccLength($spec);
2882 $this->ecccode = array_fill(0, $this->eccLength, 0);
2883 $this->blocks = QRspec::rsBlockNum($spec);
2884
2885 $ret = $this->init($spec);
2886 if($ret < 0) {
2887 throw new Exception('block alloc error');
2888 return null;
2889 }
2890
2891 $this->count = 0;
2892 }
2893
2894 //----------------------------------------------------------------------
2895 public function init(array $spec)
2896 {
2897 $dl = QRspec::rsDataCodes1($spec);
2898 $el = QRspec::rsEccCodes1($spec);
2899 $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
2900
2901
2902 $blockNo = 0;
2903 $dataPos = 0;
2904 $eccPos = 0;
2905 for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {
2906 $ecc = array_slice($this->ecccode,$eccPos);
2907 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
2908 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
2909
2910 $dataPos += $dl;
2911 $eccPos += $el;
2912 $blockNo++;
2913 }
2914
2915 if(QRspec::rsBlockNum2($spec) == 0)
2916 return 0;
2917
2918 $dl = QRspec::rsDataCodes2($spec);
2919 $el = QRspec::rsEccCodes2($spec);
2920 $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
2921
2922 if($rs == NULL) return -1;
2923
2924 for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {
2925 $ecc = array_slice($this->ecccode,$eccPos);
2926 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
2927 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
2928
2929 $dataPos += $dl;
2930 $eccPos += $el;
2931 $blockNo++;
2932 }
2933
2934 return 0;
2935 }
2936
2937 //----------------------------------------------------------------------
2938 public function getCode()
2939 {
2940 $ret = 0;
2941
2942 if($this->count < $this->dataLength) {
2943 $row = $this->count % $this->blocks;
2944 $col = $this->count / $this->blocks;
2945 if($col >= $this->rsblocks[0]->dataLength) {
2946 $row += $this->b1;
2947 }
2948 $ret = $this->rsblocks[$row]->data[$col];
2949 } else if($this->count < $this->dataLength + $this->eccLength) {
2950 $row = ($this->count - $this->dataLength) % $this->blocks;
2951 $col = ($this->count - $this->dataLength) / $this->blocks;
2952 $ret = $this->rsblocks[$row]->ecc[$col];
2953 } else {
2954 return 0;
2955 }
2956 $this->count++;
2957
2958 return $ret;
2959 }
2960 }
2961
2962 //##########################################################################
2963
2964 class QRcode {
2965
2966 public $version;
2967 public $width;
2968 public $data;
2969
2970 //----------------------------------------------------------------------
2971 public function encodeMask(QRinput $input, $mask)
2972 {
2973 if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
2974 throw new Exception('wrong version');
2975 }
2976 if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
2977 throw new Exception('wrong level');
2978 }
2979
2980 $raw = new QRrawcode($input);
2981
2982 QRtools::markTime('after_raw');
2983
2984 $version = $raw->version;
2985 $width = QRspec::getWidth($version);
2986 $frame = QRspec::newFrame($version);
2987
2988 $filler = new FrameFiller($width, $frame);
2989 if(is_null($filler)) {
2990 return NULL;
2991 }
2992
2993 // inteleaved data and ecc codes
2994 for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
2995 $code = $raw->getCode();
2996 $bit = 0x80;
2997 for($j=0; $j<8; $j++) {
2998 $addr = $filler->next();
2999 $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
3000 $bit = $bit >> 1;
3001 }
3002 }
3003
3004 QRtools::markTime('after_filler');
3005
3006 unset($raw);
3007
3008 // remainder bits
3009 $j = QRspec::getRemainder($version);
3010 for($i=0; $i<$j; $i++) {
3011 $addr = $filler->next();
3012 $filler->setFrameAt($addr, 0x02);
3013 }
3014
3015 $frame = $filler->frame;
3016 unset($filler);
3017
3018
3019 // masking
3020 $maskObj = new QRmask();
3021 if($mask < 0) {
3022
3023 if (QR_FIND_BEST_MASK) {
3024 $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
3025 } else {
3026 $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
3027 }
3028 } else {
3029 $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
3030 }
3031
3032 if($masked == NULL) {
3033 return NULL;
3034 }
3035
3036 QRtools::markTime('after_mask');
3037
3038 $this->version = $version;
3039 $this->width = $width;
3040 $this->data = $masked;
3041
3042 return $this;
3043 }
3044
3045 //----------------------------------------------------------------------
3046 public function encodeInput(QRinput $input)
3047 {
3048 return $this->encodeMask($input, -1);
3049 }
3050
3051 //----------------------------------------------------------------------
3052 public function encodeString8bit($string, $version, $level)
3053 {
3054 if(string == NULL) {
3055 throw new Exception('empty string!');
3056 return NULL;
3057 }
3058
3059 $input = new QRinput($version, $level);
3060 if($input == NULL) return NULL;
3061
3062 $ret = $input->append(QR_MODE_8, strlen($string), str_split($string));
3063 if($ret < 0) {
3064 unset($input);
3065 return NULL;
3066 }
3067 return $this->encodeInput($input);
3068 }
3069
3070 //----------------------------------------------------------------------
3071 public function encodeString($string, $version, $level, $hint, $casesensitive)
3072 {
3073
3074 if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
3075 throw new Exception('bad hint');
3076 return NULL;
3077 }
3078
3079 $input = new QRinput($version, $level);
3080 if($input == NULL) return NULL;
3081
3082 $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
3083 if($ret < 0) {
3084 return NULL;
3085 }
3086
3087 return $this->encodeInput($input);
3088 }
3089
3090 //----------------------------------------------------------------------
3091 public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false)
3092 {
3093 $enc = QRencode::factory($level, $size, $margin);
3094 return $enc->encodePNG($text, $outfile, $saveandprint=false);
3095 }
3096
3097 //----------------------------------------------------------------------
3098 public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
3099 {
3100 $enc = QRencode::factory($level, $size, $margin);
3101 return $enc->encode($text, $outfile);
3102 }
3103
3104 //----------------------------------------------------------------------
3105 public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
3106 {
3107 $enc = QRencode::factory($level, $size, $margin);
3108 return $enc->encodeRAW($text, $outfile);
3109 }
3110 }
3111
3112 //##########################################################################
3113
3114 class FrameFiller {
3115
3116 public $width;
3117 public $frame;
3118 public $x;
3119 public $y;
3120 public $dir;
3121 public $bit;
3122
3123 //----------------------------------------------------------------------
3124 public function __construct($width, &$frame)
3125 {
3126 $this->width = $width;
3127 $this->frame = $frame;
3128 $this->x = $width - 1;
3129 $this->y = $width - 1;
3130 $this->dir = -1;
3131 $this->bit = -1;
3132 }
3133
3134 //----------------------------------------------------------------------
3135 public function setFrameAt($at, $val)
3136 {
3137 $this->frame[$at['y']][$at['x']] = chr($val);
3138 }
3139
3140 //----------------------------------------------------------------------
3141 public function getFrameAt($at)
3142 {
3143 return ord($this->frame[$at['y']][$at['x']]);
3144 }
3145
3146 //----------------------------------------------------------------------
3147 public function next()
3148 {
3149 do {
3150
3151 if($this->bit == -1) {
3152 $this->bit = 0;
3153 return array('x'=>$this->x, 'y'=>$this->y);
3154 }
3155
3156 $x = $this->x;
3157 $y = $this->y;
3158 $w = $this->width;
3159
3160 if($this->bit == 0) {
3161 $x--;
3162 $this->bit++;
3163 } else {
3164 $x++;
3165 $y += $this->dir;
3166 $this->bit--;
3167 }
3168
3169 if($this->dir < 0) {
3170 if($y < 0) {
3171 $y = 0;
3172 $x -= 2;
3173 $this->dir = 1;
3174 if($x == 6) {
3175 $x--;
3176 $y = 9;
3177 }
3178 }
3179 } else {
3180 if($y == $w) {
3181 $y = $w - 1;
3182 $x -= 2;
3183 $this->dir = -1;
3184 if($x == 6) {
3185 $x--;
3186 $y -= 8;
3187 }
3188 }
3189 }
3190 if($x < 0 || $y < 0) return null;
3191
3192 $this->x = $x;
3193 $this->y = $y;
3194
3195 } while(ord($this->frame[$y][$x]) & 0x80);
3196
3197 return array('x'=>$x, 'y'=>$y);
3198 }
3199
3200 } ;
3201
3202 //##########################################################################
3203
3204 class QRencode {
3205
3206 public $casesensitive = true;
3207 public $eightbit = false;
3208
3209 public $version = 0;
3210 public $size = 3;
3211 public $margin = 4;
3212
3213 public $structured = 0; // not supported yet
3214
3215 public $level = QR_ECLEVEL_L;
3216 public $hint = QR_MODE_8;
3217
3218 //----------------------------------------------------------------------
3219 public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)
3220 {
3221 $enc = new QRencode();
3222 $enc->size = $size;
3223 $enc->margin = $margin;
3224
3225 switch ($level.'') {
3226 case '0':
3227 case '1':
3228 case '2':
3229 case '3':
3230 $enc->level = $level;
3231 break;
3232 case 'l':
3233 case 'L':
3234 $enc->level = QR_ECLEVEL_L;
3235 break;
3236 case 'm':
3237 case 'M':
3238 $enc->level = QR_ECLEVEL_M;
3239 break;
3240 case 'q':
3241 case 'Q':
3242 $enc->level = QR_ECLEVEL_Q;
3243 break;
3244 case 'h':
3245 case 'H':
3246 $enc->level = QR_ECLEVEL_H;
3247 break;
3248 }
3249
3250 return $enc;
3251 }
3252
3253 //----------------------------------------------------------------------
3254 public function encodeRAW($intext, $outfile = false)
3255 {
3256 $code = new QRcode();
3257
3258 if($this->eightbit) {
3259 $code->encodeString8bit($intext, $this->version, $this->level);
3260 } else {
3261 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
3262 }
3263
3264 return $code->data;
3265 }
3266
3267 //----------------------------------------------------------------------
3268 public function encode($intext, $outfile = false)
3269 {
3270 $code = new QRcode();
3271
3272 if($this->eightbit) {
3273 $code->encodeString8bit($intext, $this->version, $this->level);
3274 } else {
3275 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
3276 }
3277
3278 QRtools::markTime('after_encode');
3279
3280 if ($outfile!== false) {
3281 file_put_contents($outfile, join("\n", QRtools::binarize($code->data)));
3282 } else {
3283 return QRtools::binarize($code->data);
3284 }
3285 }
3286
3287 //----------------------------------------------------------------------
3288 public function encodePNG($intext, $outfile = false,$saveandprint=false)
3289 {
3290 try {
3291
3292 ob_start();
3293 $tab = $this->encode($intext);
3294 $err = ob_get_contents();
3295 ob_end_clean();
3296
3297 if ($err != '')
3298 QRtools::log($outfile, $err);
3299
3300 $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
3301
3302 QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
3303
3304 } catch (Exception $e) {
3305
3306 QRtools::log($outfile, $e->getMessage());
3307
3308 }
3309 }
3310 }
3311
3312