@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
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.9.9
40 * Build: 20130526
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-2013 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
78 /** \defgroup QR_CONST Global Constants
79 Constant used globally for function arguments.
80 Make PHP calls a little bit more clear, in place of missing (in dynamicaly typed language) enum types.
81 * @{
82 */
83
84 /** @name QR-Code Encoding Modes */
85 /** @{ */
86
87 /** null encoding, used when no encoding was speciffied yet */
88 define('QR_MODE_NUL', -1);
89 /** Numerical encoding, only numbers (0-9) */
90 define('QR_MODE_NUM', 0);
91 /** AlphaNumerical encoding, numbers (0-9) uppercase text (A-Z) and few special characters (space, $, %, *, +, -, ., /, :) */
92 define('QR_MODE_AN', 1);
93 /** 8-bit encoding, raw 8 bit encoding */
94 define('QR_MODE_8', 2);
95 /** Kanji encoding */
96 define('QR_MODE_KANJI', 3);
97 /** Structure, internal encoding for structure-related data */
98 define('QR_MODE_STRUCTURE', 4);
99 /**@}*/
100
101 /** @name QR-Code Levels of Error Correction
102 Constants speciffy ECC level from lowest __L__ to the highest __H__.
103 Higher levels are recomended for Outdoor-presented codes, but generates bigger codes.
104 */
105 /** @{*/
106 /** ~7% of codewords can be restored */
107 define('QR_ECLEVEL_L', 0);
108 /** ~15% of codewords can be restored */
109 define('QR_ECLEVEL_M', 1);
110 /** ~25% of codewords can be restored */
111 define('QR_ECLEVEL_Q', 2);
112 /** ~30% of codewords can be restored */
113 define('QR_ECLEVEL_H', 3);
114 /** @}*/
115
116 /** @name QR-Code Supported output formats */
117 /** @{*/
118 define('QR_FORMAT_TEXT', 0);
119 define('QR_FORMAT_PNG', 1);
120 /** @}*/
121
122 /** @}*/
123
124
125
126
127//---- merged_config.php -----------------------------
128
129
130
131
132/*
133 * PHP QR Code encoder
134 *
135 * Config file, tuned-up for merged verion
136 */
137
138 define('QR_CACHEABLE', false); // use cache - more disk reads but less CPU power, masks and format templates are stored there
139 define('QR_CACHE_DIR', false); // used when QR_CACHEABLE === true
140 define('QR_LOG_DIR', false); // default error logs dir
141
142 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
143 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
144 define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
145
146 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
147
148
149
150
151//---- qrtools.php -----------------------------
152
153
154
155
156/*
157 * PHP QR Code encoder
158 *
159 * Toolset, handy and debug utilites.
160 *
161 * PHP QR Code is distributed under LGPL 3
162 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
163 *
164 * This library is free software; you can redistribute it and/or
165 * modify it under the terms of the GNU Lesser General Public
166 * License as published by the Free Software Foundation; either
167 * version 3 of the License, or any later version.
168 *
169 * This library is distributed in the hope that it will be useful,
170 * but WITHOUT ANY WARRANTY; without even the implied warranty of
171 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
172 * Lesser General Public License for more details.
173 *
174 * You should have received a copy of the GNU Lesser General Public
175 * License along with this library; if not, write to the Free Software
176 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
177 */
178
179 /** @addtogroup CoreGroup */
180 /** @{ */
181
182 /** Helper class */
183 class QRtools {
184
185 public static $timeBenchmarkStarted = false;
186
187 //----------------------------------------------------------------------
188 public static function binarize($frame)
189 {
190 $len = count($frame);
191 foreach ($frame as &$frameLine) {
192
193 for($i=0; $i<$len; $i++) {
194 $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
195 }
196 }
197
198 return $frame;
199 }
200
201 //----------------------------------------------------------------------
202 public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037')
203 {
204 $barcode_array = array();
205
206 if (!is_array($mode))
207 $mode = explode(',', $mode);
208
209 $eccLevel = 'L';
210
211 if (count($mode) > 1) {
212 $eccLevel = $mode[1];
213 }
214
215 $qrTab = QRcode::text($code, false, $eccLevel);
216 $size = count($qrTab);
217
218 $barcode_array['num_rows'] = $size;
219 $barcode_array['num_cols'] = $size;
220 $barcode_array['bcode'] = array();
221
222 foreach ($qrTab as $line) {
223 $arrAdd = array();
224 foreach(str_split($line) as $char)
225 $arrAdd[] = ($char=='1')?1:0;
226 $barcode_array['bcode'][] = $arrAdd;
227 }
228
229 return $barcode_array;
230 }
231
232 //----------------------------------------------------------------------
233 public static function clearCache()
234 {
235 self::$frames = array();
236 }
237
238 //----------------------------------------------------------------------
239 public static function buildCache()
240 {
241 QRtools::markTime('before_build_cache');
242
243 $mask = new QRmask();
244 for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) {
245 $frame = QRspec::newFrame($a);
246 if (QR_IMAGE) {
247 $fileName = QR_CACHE_DIR.'frame_'.$a.'.png';
248 QRimage::png(self::binarize($frame), $fileName, 1, 0);
249 }
250
251 $width = count($frame);
252 $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
253 for ($maskNo=0; $maskNo<8; $maskNo++)
254 $mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true);
255 }
256
257 QRtools::markTime('after_build_cache');
258 }
259
260 //----------------------------------------------------------------------
261 public static function log($outfile, $err)
262 {
263 if (QR_LOG_DIR !== false) {
264 if ($err != '') {
265 if ($outfile !== false) {
266 file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
267 } else {
268 file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
269 }
270 }
271 }
272 }
273
274 //----------------------------------------------------------------------
275 public static function dumpMask($frame)
276 {
277 $width = count($frame);
278 for($y=0;$y<$width;$y++) {
279 for($x=0;$x<$width;$x++) {
280 echo ord($frame[$y][$x]).',';
281 }
282 }
283 }
284
285 //----------------------------------------------------------------------
286 public static function startTimeBenchmark()
287 {
288 $GLOBALS['qr_time_bench'] = array();
289 self::markTime('start');
290 }
291
292 //----------------------------------------------------------------------
293 public static function markTime($markerId)
294 {
295 list($usec, $sec) = explode(" ", microtime());
296 $time = ((float)$usec + (float)$sec);
297
298 if (!isset($GLOBALS['qr_time_bench']))
299 $GLOBALS['qr_time_bench'] = array();
300
301 $GLOBALS['qr_time_bench'][$markerId] = $time;
302
303 if ((!self::$timeBenchmarkStarted)&&($markerId != 'start')) {
304 self::$timeBenchmarkStarted = true;
305 $GLOBALS['qr_time_bench']['start'] = $time;
306 }
307 }
308
309 //----------------------------------------------------------------------
310 public static function timeBenchmark()
311 {
312 self::markTime('finish');
313
314 $lastTime = 0;
315 $startTime = 0;
316 $p = 0;
317
318 echo '<table cellpadding="3" cellspacing="1">
319 <thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
320 <tbody>';
321
322 foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {
323 if ($p > 0) {
324 echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>';
325 } else {
326 $startTime = $thisTime;
327 }
328
329 $p++;
330 $lastTime = $thisTime;
331 }
332
333 echo '</tbody><tfoot>
334 <tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>
335 </tfoot>
336 </table>';
337 }
338
339 }
340
341 /** @}*/
342
343 //##########################################################################
344
345
346
347
348//---- qrspec.php -----------------------------
349
350
351
352
353/*
354 * PHP QR Code encoder
355 *
356 * QR Code specifications
357 *
358 * Based on libqrencode C library distributed under LGPL 2.1
359 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
360 *
361 * PHP QR Code is distributed under LGPL 3
362 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
363 *
364 * The following data / specifications are taken from
365 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
366 * or
367 * "Automatic identification and data capture techniques --
368 * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
369 *
370 * This library is free software; you can redistribute it and/or
371 * modify it under the terms of the GNU Lesser General Public
372 * License as published by the Free Software Foundation; either
373 * version 3 of the License, or any later version.
374 *
375 * This library is distributed in the hope that it will be useful,
376 * but WITHOUT ANY WARRANTY; without even the implied warranty of
377 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
378 * Lesser General Public License for more details.
379 *
380 * You should have received a copy of the GNU Lesser General Public
381 * License along with this library; if not, write to the Free Software
382 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
383 */
384
385 /** Maximal Version no allowed by QR-Code spec */
386 define('QRSPEC_VERSION_MAX', 40);
387 /** Maximal Code size in pixels allowed by QR-Code spec */
388 define('QRSPEC_WIDTH_MAX', 177);
389
390 define('QRCAP_WIDTH', 0);
391 define('QRCAP_WORDS', 1);
392 define('QRCAP_REMINDER', 2);
393 define('QRCAP_EC', 3);
394
395 /** @addtogroup CoreGroup */
396 /** @{ */
397
398 /** QR-Code specification and Code Frame handling.
399 Contains code specifications, calculates base frame, code structure
400 and base properties
401 */
402 class QRspec {
403
404 /** Array specifying properties of QR-Code "versions".
405 Each so-called version has specified code area size and capacity.
406 There are 40 versions, this table specifies for each of them four parameters:
407
408 - Integer __QRCAP_WIDTH__ - size of code in pixels
409 - Integer __QRCAP_WORDS__ - code capacity, in words
410 - Integer __QRCAP_REMINDER__ - remainder words
411 - Array of Integers __QRCAP_EC__ - RS correction code count for each of four ECC levels
412 \hideinitializer
413 */
414 public static $capacity = array(
415 array( 0, 0, 0, array( 0, 0, 0, 0)),
416 array( 21, 26, 0, array( 7, 10, 13, 17)), // 1
417 array( 25, 44, 7, array( 10, 16, 22, 28)),
418 array( 29, 70, 7, array( 15, 26, 36, 44)),
419 array( 33, 100, 7, array( 20, 36, 52, 64)),
420 array( 37, 134, 7, array( 26, 48, 72, 88)), // 5
421 array( 41, 172, 7, array( 36, 64, 96, 112)),
422 array( 45, 196, 0, array( 40, 72, 108, 130)),
423 array( 49, 242, 0, array( 48, 88, 132, 156)),
424 array( 53, 292, 0, array( 60, 110, 160, 192)),
425 array( 57, 346, 0, array( 72, 130, 192, 224)), //10
426 array( 61, 404, 0, array( 80, 150, 224, 264)),
427 array( 65, 466, 0, array( 96, 176, 260, 308)),
428 array( 69, 532, 0, array( 104, 198, 288, 352)),
429 array( 73, 581, 3, array( 120, 216, 320, 384)),
430 array( 77, 655, 3, array( 132, 240, 360, 432)), //15
431 array( 81, 733, 3, array( 144, 280, 408, 480)),
432 array( 85, 815, 3, array( 168, 308, 448, 532)),
433 array( 89, 901, 3, array( 180, 338, 504, 588)),
434 array( 93, 991, 3, array( 196, 364, 546, 650)),
435 array( 97, 1085, 3, array( 224, 416, 600, 700)), //20
436 array(101, 1156, 4, array( 224, 442, 644, 750)),
437 array(105, 1258, 4, array( 252, 476, 690, 816)),
438 array(109, 1364, 4, array( 270, 504, 750, 900)),
439 array(113, 1474, 4, array( 300, 560, 810, 960)),
440 array(117, 1588, 4, array( 312, 588, 870, 1050)), //25
441 array(121, 1706, 4, array( 336, 644, 952, 1110)),
442 array(125, 1828, 4, array( 360, 700, 1020, 1200)),
443 array(129, 1921, 3, array( 390, 728, 1050, 1260)),
444 array(133, 2051, 3, array( 420, 784, 1140, 1350)),
445 array(137, 2185, 3, array( 450, 812, 1200, 1440)), //30
446 array(141, 2323, 3, array( 480, 868, 1290, 1530)),
447 array(145, 2465, 3, array( 510, 924, 1350, 1620)),
448 array(149, 2611, 3, array( 540, 980, 1440, 1710)),
449 array(153, 2761, 3, array( 570, 1036, 1530, 1800)),
450 array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35
451 array(161, 3034, 0, array( 600, 1120, 1680, 1980)),
452 array(165, 3196, 0, array( 630, 1204, 1770, 2100)),
453 array(169, 3362, 0, array( 660, 1260, 1860, 2220)),
454 array(173, 3532, 0, array( 720, 1316, 1950, 2310)),
455 array(177, 3706, 0, array( 750, 1372, 2040, 2430)) //40
456 );
457
458 //----------------------------------------------------------------------
459 /** Calculates data length for specified code configuration.
460 @param Integer $version Code version
461 @param Integer $level ECC level
462 @returns Code data capacity
463 */
464 public static function getDataLength($version, $level)
465 {
466 return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level];
467 }
468
469 //----------------------------------------------------------------------
470 /** Calculates count of Error Correction Codes for specified code configuration.
471 @param Integer $version Code version
472 @param Integer $level ECC level
473 @returns ECC code count
474 */
475 public static function getECCLength($version, $level)
476 {
477 return self::$capacity[$version][QRCAP_EC][$level];
478 }
479
480 //----------------------------------------------------------------------
481 /** Gets pixel width of code.
482 @param Integer $version Code version
483 @returns Code width, in pixels
484 */
485 public static function getWidth($version)
486 {
487 return self::$capacity[$version][QRCAP_WIDTH];
488 }
489
490 //----------------------------------------------------------------------
491 /** Gets reminder chars length.
492 @param Integer $version Code version
493 @returns Reminder length
494 */
495 public static function getRemainder($version)
496 {
497 return self::$capacity[$version][QRCAP_REMINDER];
498 }
499
500 //----------------------------------------------------------------------
501 /** Finds minimal code version capable of hosting specified data length.
502 @param Integer $size amount of raw data
503 @param Integer $level ECC level
504 @returns code version capable of hosting specified amount of data at specified ECC level
505 */
506 public static function getMinimumVersion($size, $level)
507 {
508
509 for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) {
510 $words = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level];
511 if($words >= $size)
512 return $i;
513 }
514
515 return -1;
516 }
517
518 //######################################################################
519
520 /** Length bits Table.
521 \hideinitializer
522 */
523 public static $lengthTableBits = array(
524 array(10, 12, 14),
525 array( 9, 11, 13),
526 array( 8, 16, 16),
527 array( 8, 10, 12)
528 );
529
530 //----------------------------------------------------------------------
531 public static function lengthIndicator($mode, $version)
532 {
533 if ($mode == QR_MODE_STRUCTURE)
534 return 0;
535
536 if ($version <= 9) {
537 $l = 0;
538 } else if ($version <= 26) {
539 $l = 1;
540 } else {
541 $l = 2;
542 }
543
544 return self::$lengthTableBits[$mode][$l];
545 }
546
547 //----------------------------------------------------------------------
548 public static function maximumWords($mode, $version)
549 {
550 if($mode == QR_MODE_STRUCTURE)
551 return 3;
552
553 if($version <= 9) {
554 $l = 0;
555 } else if($version <= 26) {
556 $l = 1;
557 } else {
558 $l = 2;
559 }
560
561 $bits = self::$lengthTableBits[$mode][$l];
562 $words = (1 << $bits) - 1;
563
564 if($mode == QR_MODE_KANJI) {
565 $words *= 2; // the number of bytes is required
566 }
567
568 return $words;
569 }
570
571 // Error correction code -----------------------------------------------
572 /** Table of the error correction code (Reed-Solomon block).
573 @see Table 12-16 (pp.30-36), JIS X0510:2004.
574 \hideinitializer
575 */
576
577 public static $eccTable = array(
578 array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)),
579 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1
580 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)),
581 array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)),
582 array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)),
583 array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5
584 array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)),
585 array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)),
586 array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)),
587 array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)),
588 array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), //10
589 array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)),
590 array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)),
591 array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)),
592 array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)),
593 array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), //15
594 array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)),
595 array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)),
596 array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)),
597 array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)),
598 array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), //20
599 array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)),
600 array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)),
601 array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)),
602 array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)),
603 array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), //25
604 array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)),
605 array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)),
606 array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)),
607 array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)),
608 array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30
609 array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)),
610 array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)),
611 array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)),
612 array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)),
613 array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), //35
614 array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)),
615 array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)),
616 array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)),
617 array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)),
618 array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)),//40
619 );
620
621 //----------------------------------------------------------------------
622 // CACHEABLE!!!
623
624 public static function getEccSpec($version, $level, array &$spec)
625 {
626 if (count($spec) < 5) {
627 $spec = array(0,0,0,0,0);
628 }
629
630 $b1 = self::$eccTable[$version][$level][0];
631 $b2 = self::$eccTable[$version][$level][1];
632 $data = self::getDataLength($version, $level);
633 $ecc = self::getECCLength($version, $level);
634
635 if($b2 == 0) {
636 $spec[0] = $b1;
637 $spec[1] = (int)($data / $b1);
638 $spec[2] = (int)($ecc / $b1);
639 $spec[3] = 0;
640 $spec[4] = 0;
641 } else {
642 $spec[0] = $b1;
643 $spec[1] = (int)($data / ($b1 + $b2));
644 $spec[2] = (int)($ecc / ($b1 + $b2));
645 $spec[3] = $b2;
646 $spec[4] = $spec[1] + 1;
647 }
648 }
649
650 // Alignment pattern ---------------------------------------------------
651
652 /** Positions of alignment patterns.
653 This array includes only the second and the third position of the
654 lignment patterns. Rest of them can be calculated from the distance
655 between them.
656
657 @see Table 1 in Appendix E (pp.71) of JIS X0510:2004.
658 \hideinitializer
659 */
660
661 public static $alignmentPattern = array(
662 array( 0, 0),
663 array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
664 array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
665 array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15
666 array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20
667 array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25
668 array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30
669 array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35
670 array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40
671 );
672
673 //----------------------------------------------------------------------
674 /** Puts an alignment marker.
675 @param frame
676 @param width
677 @param ox,oy center coordinate of the pattern
678 */
679 public static function putAlignmentMarker(array &$frame, $ox, $oy)
680 {
681 $finder = array(
682 "\xa1\xa1\xa1\xa1\xa1",
683 "\xa1\xa0\xa0\xa0\xa1",
684 "\xa1\xa0\xa1\xa0\xa1",
685 "\xa1\xa0\xa0\xa0\xa1",
686 "\xa1\xa1\xa1\xa1\xa1"
687 );
688
689 $yStart = $oy-2;
690 $xStart = $ox-2;
691
692 for($y=0; $y<5; $y++) {
693 self::set($frame, $xStart, $yStart+$y, $finder[$y]);
694 }
695 }
696
697 //----------------------------------------------------------------------
698 public static function putAlignmentPattern($version, &$frame, $width)
699 {
700 if($version < 2)
701 return;
702
703 $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0];
704 if($d < 0) {
705 $w = 2;
706 } else {
707 $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2);
708 }
709
710 if($w * $w - 3 == 1) {
711 $x = self::$alignmentPattern[$version][0];
712 $y = self::$alignmentPattern[$version][0];
713 self::putAlignmentMarker($frame, $x, $y);
714 return;
715 }
716
717 $cx = self::$alignmentPattern[$version][0];
718 for($x=1; $x<$w - 1; $x++) {
719 self::putAlignmentMarker($frame, 6, $cx);
720 self::putAlignmentMarker($frame, $cx, 6);
721 $cx += $d;
722 }
723
724 $cy = self::$alignmentPattern[$version][0];
725 for($y=0; $y<$w-1; $y++) {
726 $cx = self::$alignmentPattern[$version][0];
727 for($x=0; $x<$w-1; $x++) {
728 self::putAlignmentMarker($frame, $cx, $cy);
729 $cx += $d;
730 }
731 $cy += $d;
732 }
733 }
734
735 // Version information pattern -----------------------------------------
736 /** Version information pattern (BCH coded).
737 size: [QRSPEC_VERSION_MAX - 6]
738 @see Table 1 in Appendix D (pp.68) of JIS X0510:2004.
739 \hideinitializer
740 */
741
742 public static $versionPattern = array(
743 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
744 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
745 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
746 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
747 0x27541, 0x28c69
748 );
749
750 //----------------------------------------------------------------------
751 public static function getVersionPattern($version)
752 {
753 if($version < 7 || $version > QRSPEC_VERSION_MAX)
754 return 0;
755
756 return self::$versionPattern[$version -7];
757 }
758
759 //----------------------------------------------------------------------
760 /** Format information.
761 @see calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)
762 \hideinitializer
763 */
764
765 public static $formatInfo = array(
766 array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976),
767 array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0),
768 array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed),
769 array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)
770 );
771
772 public static function getFormatInfo($mask, $level)
773 {
774 if($mask < 0 || $mask > 7)
775 return 0;
776
777 if($level < 0 || $level > 3)
778 return 0;
779
780 return self::$formatInfo[$level][$mask];
781 }
782
783 // Frame ---------------------------------------------------------------
784
785 /** Cache of initial frames. */
786 public static $frames = array();
787
788 /** Put a finder pattern.
789 @param frame
790 @param width
791 @param ox,oy upper-left coordinate of the pattern
792 \hideinitializer
793 */
794 public static function putFinderPattern(&$frame, $ox, $oy)
795 {
796 $finder = array(
797 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
798 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
799 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
800 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
801 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
802 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
803 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
804 );
805
806 for($y=0; $y<7; $y++) {
807 self::set($frame, $ox, $oy+$y, $finder[$y]);
808 }
809 }
810
811 //----------------------------------------------------------------------
812 public static function createFrame($version)
813 {
814 $width = self::$capacity[$version][QRCAP_WIDTH];
815 $frameLine = str_repeat ("\0", $width);
816 $frame = array_fill(0, $width, $frameLine);
817
818 // Finder pattern
819 self::putFinderPattern($frame, 0, 0);
820 self::putFinderPattern($frame, $width - 7, 0);
821 self::putFinderPattern($frame, 0, $width - 7);
822
823 // Separator
824 $yOffset = $width - 7;
825
826 for($y=0; $y<7; $y++) {
827 $frame[$y][7] = "\xc0";
828 $frame[$y][$width - 8] = "\xc0";
829 $frame[$yOffset][7] = "\xc0";
830 $yOffset++;
831 }
832
833 $setPattern = str_repeat("\xc0", 8);
834
835 self::set($frame, 0, 7, $setPattern);
836 self::set($frame, $width-8, 7, $setPattern);
837 self::set($frame, 0, $width - 8, $setPattern);
838
839 // Format info
840 $setPattern = str_repeat("\x84", 9);
841 self::set($frame, 0, 8, $setPattern);
842 self::set($frame, $width - 8, 8, $setPattern, 8);
843
844 $yOffset = $width - 8;
845
846 for($y=0; $y<8; $y++,$yOffset++) {
847 $frame[$y][8] = "\x84";
848 $frame[$yOffset][8] = "\x84";
849 }
850
851 // Timing pattern
852
853 for($i=1; $i<$width-15; $i++) {
854 $frame[6][7+$i] = chr(0x90 | ($i & 1));
855 $frame[7+$i][6] = chr(0x90 | ($i & 1));
856 }
857
858 // Alignment pattern
859 self::putAlignmentPattern($version, $frame, $width);
860
861 // Version information
862 if($version >= 7) {
863 $vinf = self::getVersionPattern($version);
864
865 $v = $vinf;
866
867 for($x=0; $x<6; $x++) {
868 for($y=0; $y<3; $y++) {
869 $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
870 $v = $v >> 1;
871 }
872 }
873
874 $v = $vinf;
875 for($y=0; $y<6; $y++) {
876 for($x=0; $x<3; $x++) {
877 $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
878 $v = $v >> 1;
879 }
880 }
881 }
882
883 // and a little bit...
884 $frame[$width - 8][8] = "\x81";
885
886 return $frame;
887 }
888
889 //----------------------------------------------------------------------
890 /** Dumps debug HTML of frame.
891 @param Array $frame code frame
892 @param Boolean $binary_mode in binary mode only contents is dumped, without styling
893 */
894 public static function debug($frame, $binary_mode = false)
895 {
896 if ($binary_mode) {
897
898 foreach ($frame as &$frameLine) {
899 $frameLine = join('<span class="m"> </span>', explode('0', $frameLine));
900 $frameLine = join('██', explode('1', $frameLine));
901 }
902
903 echo '<style> .m { background-color: white; } </style> ';
904 echo '<pre><tt><br/ ><br/ ><br/ > ';
905 echo join("<br/ > ", $frame);
906 echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';
907
908 } else {
909
910 foreach ($frame as &$frameLine) {
911
912 $frameLine = strtr($frameLine, array(
913 "\xc0" => '<span class="m"> </span>', //marker 0
914 "\xc1" => '<span class="m">▒</span>', //marker 1
915 "\xa0" => '<span class="p"> </span>', //submarker 0
916 "\xa1" => '<span class="p">▒</span>', //submarker 1
917 "\x84" => '<span class="s">F</span>', //format 0
918 "\x85" => '<span class="s">f</span>', //format 1
919 "\x81" => '<span class="x">S</span>', //special bit
920 "\x90" => '<span class="c">C</span>', //clock 0
921 "\x91" => '<span class="c">c</span>', //clock 1
922 "\x88" => '<span class="f"> </span>', //version 0
923 "\x89" => '<span class="f">▒</span>', //version 1
924 "\x03" => '1', // 1
925 "\x02" => '0', // 0
926 ));
927 }
928
929 echo '<style>';
930 echo ' .p { background-color: yellow; }';
931 echo ' .m { background-color: #00FF00; }';
932 echo ' .s { background-color: #FF0000; }';
933 echo ' .c { background-color: aqua; }';
934 echo ' .x { background-color: pink; }';
935 echo ' .f { background-color: gold; }';
936 echo '</style>';
937
938 echo "<tt>";
939 echo join("<br/ >", $frame);
940 echo "<br/>Legend:<br/>";
941 echo '1 - data 1<br/>';
942 echo '0 - data 0<br/>';
943 echo '<span class="m"> </span> - marker bit 0<br/>';
944 echo '<span class="m">▒</span> - marker bit 1<br/>';
945 echo '<span class="p"> </span> - secondary marker bit 0<br/>';
946 echo '<span class="p">▒</span> - secondary marker bit 1<br/>';
947 echo '<span class="s">F</span> - format bit 0<br/>';
948 echo '<span class="s">f</span> - format bit 1<br/>';
949 echo '<span class="x">S</span> - special bit<br/>';
950 echo '<span class="c">C</span> - clock bit 0<br/>';
951 echo '<span class="c">c</span> - clock bit 1<br/>';
952 echo '<span class="f"> </span> - version bit 0<br/>';
953 echo '<span class="f">▒</span> - version bit 1<br/>';
954 echo "</tt>";
955
956 }
957 }
958
959 //----------------------------------------------------------------------
960 /** Serializes frame.
961 Create compressed, serialized version of frame.
962 @param Array $frame Code Frame
963 @return String binary compresed Code Frame
964 */
965 public static function serial($frame)
966 {
967 return gzcompress(join("\n", $frame), 9);
968 }
969
970 //----------------------------------------------------------------------
971 /** Deserializes frame.
972 Loads frame from serialized compressed binary
973 @param String $code binary, GZipped, serialized frame
974 @return Array Code Frame array
975 */
976 public static function unserial($code)
977 {
978 return explode("\n", gzuncompress($code));
979 }
980
981 //----------------------------------------------------------------------
982 public static function newFrame($version)
983 {
984 if($version < 1 || $version > QRSPEC_VERSION_MAX)
985 return null;
986
987 if(!isset(self::$frames[$version])) {
988
989 $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat';
990
991 if (QR_CACHEABLE) {
992 if (file_exists($fileName)) {
993 self::$frames[$version] = self::unserial(file_get_contents($fileName));
994 } else {
995 self::$frames[$version] = self::createFrame($version);
996 file_put_contents($fileName, self::serial(self::$frames[$version]));
997 }
998 } else {
999 self::$frames[$version] = self::createFrame($version);
1000 }
1001 }
1002
1003 if(is_null(self::$frames[$version]))
1004 return null;
1005
1006 return self::$frames[$version];
1007 }
1008
1009 //----------------------------------------------------------------------
1010 /** Sets code frame with speciffied code.
1011 @param Array $frame target frame (modified by reference)
1012 @param Integer $x X-axis position of replacement
1013 @param Integer $y Y-axis position of replacement
1014 @param Byte $repl replacement string
1015 @param Integer $replLen (optional) replacement string length, when __Integer__ > 1 subset of given $repl is used, when __false__ whole $repl is used
1016 */
1017 public static function set(&$frame, $x, $y, $repl, $replLen = false) {
1018 $frame[$y] = substr_replace($frame[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
1019 }
1020
1021 //----------------------------------------------------------------------
1022
1023 /** @name Reed-Solomon related shorthand getters.
1024 Syntax-sugar to access code speciffication by getter name, not by spec array field.
1025 */
1026 /** @{*/
1027 public static function rsBlockNum($spec) { return $spec[0] + $spec[3]; }
1028 public static function rsBlockNum1($spec) { return $spec[0]; }
1029 public static function rsDataCodes1($spec) { return $spec[1]; }
1030 public static function rsEccCodes1($spec) { return $spec[2]; }
1031 public static function rsBlockNum2($spec) { return $spec[3]; }
1032 public static function rsDataCodes2($spec) { return $spec[4]; }
1033 public static function rsEccCodes2($spec) { return $spec[2]; }
1034 public static function rsDataLength($spec) { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); }
1035 public static function rsEccLength($spec) { return ($spec[0] + $spec[3]) * $spec[2]; }
1036 /** @}*/
1037 }
1038
1039 /** @}*/
1040
1041
1042
1043
1044
1045//---- qrimage.php -----------------------------
1046
1047
1048
1049
1050/*
1051 * PHP QR Code encoder
1052 *
1053 * Image output of code using GD2
1054 *
1055 * PHP QR Code is distributed under LGPL 3
1056 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
1057 *
1058 * This library is free software; you can redistribute it and/or
1059 * modify it under the terms of the GNU Lesser General Public
1060 * License as published by the Free Software Foundation; either
1061 * version 3 of the License, or any later version.
1062 *
1063 * This library is distributed in the hope that it will be useful,
1064 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1065 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1066 * Lesser General Public License for more details.
1067 *
1068 * You should have received a copy of the GNU Lesser General Public
1069 * License along with this library; if not, write to the Free Software
1070 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1071 */
1072
1073 define('QR_IMAGE', true);
1074
1075
1076 /** @defgroup OutputGroup Standard API Output
1077 Provide simple Raster & Vector output */
1078
1079 /** @addtogroup OutputGroup */
1080 /** @{ */
1081
1082 /** Image rendering helper.
1083 Uses GD2 image to render QR Code into image file */
1084 class QRimage {
1085
1086 //----------------------------------------------------------------------
1087 /**
1088 Creates PNG image.
1089 @param Array $frame frame containing code
1090 @param String $filename (optional) output file name, if __false__ outputs to browser with required headers
1091 @param Integer $pixelPerPoint (optional) pixel size, multiplier for each 'virtual' pixel
1092 @param Integer $outerFrame (optional) code margin (silent zone) in 'virtual' pixels
1093 @param Boolean $saveandprint (optional) if __true__ code is outputed to browser and saved to file, otherwise only saved to file. It is effective only if $outfile is specified.
1094 */
1095
1096 public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE)
1097 {
1098 $image = self::image($frame, $pixelPerPoint, $outerFrame);
1099
1100 if ($filename === false) {
1101 Header("Content-type: image/png");
1102 ImagePng($image);
1103 } else {
1104 if($saveandprint===TRUE){
1105 ImagePng($image, $filename);
1106 header("Content-type: image/png");
1107 ImagePng($image);
1108 }else{
1109 ImagePng($image, $filename);
1110 }
1111 }
1112
1113 ImageDestroy($image);
1114 }
1115
1116 //----------------------------------------------------------------------
1117 /**
1118 Creates JPEG image.
1119 @param Array $frame frame containing code
1120 @param String $filename (optional) output file name, if __false__ outputs to browser with required headers
1121 @param Integer $pixelPerPoint (optional) pixel size, multiplier for each 'virtual' pixel
1122 @param Integer $outerFrame (optional) code margin (silent zone) in 'virtual' pixels
1123 @param Integer $q (optional) JPEG compression level (__0__ .. __100__)
1124 */
1125
1126 public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85)
1127 {
1128 $image = self::image($frame, $pixelPerPoint, $outerFrame);
1129
1130 if ($filename === false) {
1131 Header("Content-type: image/jpeg");
1132 ImageJpeg($image, null, $q);
1133 } else {
1134 ImageJpeg($image, $filename, $q);
1135 }
1136
1137 ImageDestroy($image);
1138 }
1139
1140 //----------------------------------------------------------------------
1141 /**
1142 Creates generic GD2 image object
1143 @param Array $frame frame containing code
1144 @param Integer $pixelPerPoint (optional) pixel size, multiplier for each 'virtual' pixel
1145 @param Integer $outerFrame (optional) code margin (silent zone) in 'virtual' pixels
1146 @return __Resource__ GD2 image resource (remember to ImageDestroy it!)
1147 */
1148 public static function image($frame, $pixelPerPoint = 4, $outerFrame = 4)
1149 {
1150 $h = count($frame);
1151 $w = strlen($frame[0]);
1152
1153 $imgW = $w + 2*$outerFrame;
1154 $imgH = $h + 2*$outerFrame;
1155
1156 $base_image =ImageCreate($imgW, $imgH);
1157
1158 $col[0] = ImageColorAllocate($base_image,255,255,255);
1159 $col[1] = ImageColorAllocate($base_image,0,0,0);
1160
1161 imagefill($base_image, 0, 0, $col[0]);
1162
1163 for($y=0; $y<$h; $y++) {
1164 for($x=0; $x<$w; $x++) {
1165 if ($frame[$y][$x] == '1') {
1166 ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]);
1167 }
1168 }
1169 }
1170
1171 $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
1172 ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
1173 ImageDestroy($base_image);
1174
1175 return $target_image;
1176 }
1177 }
1178
1179 /** @} */
1180
1181
1182
1183//---- qrinput.php -----------------------------
1184
1185
1186
1187
1188/*
1189 * PHP QR Code encoder
1190 *
1191 * Input encoding class
1192 *
1193 * Based on libqrencode C library distributed under LGPL 2.1
1194 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
1195 *
1196 * PHP QR Code is distributed under LGPL 3
1197 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
1198 *
1199 * This library is free software; you can redistribute it and/or
1200 * modify it under the terms of the GNU Lesser General Public
1201 * License as published by the Free Software Foundation; either
1202 * version 3 of the License, or any later version.
1203 *
1204 * This library is distributed in the hope that it will be useful,
1205 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1206 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1207 * Lesser General Public License for more details.
1208 *
1209 * You should have received a copy of the GNU Lesser General Public
1210 * License along with this library; if not, write to the Free Software
1211 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1212 */
1213
1214 define('STRUCTURE_HEADER_BITS', 20);
1215 define('MAX_STRUCTURED_SYMBOLS', 16);
1216
1217 /** @addtogroup CoreGroup */
1218 /** @{ */
1219
1220 class QRinputItem {
1221
1222 public $mode;
1223 public $size;
1224 public $data;
1225 public $bstream;
1226
1227 public function __construct($mode, $size, $data, $bstream = null)
1228 {
1229 $setData = array_slice($data, 0, $size);
1230
1231 if (count($setData) < $size) {
1232 $setData = array_merge($setData, array_fill(0,$size-count($setData),0));
1233 }
1234
1235 if(!QRinput::check($mode, $size, $setData)) {
1236 throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
1237 return null;
1238 }
1239
1240 $this->mode = $mode;
1241 $this->size = $size;
1242 $this->data = $setData;
1243 $this->bstream = $bstream;
1244 }
1245
1246 //----------------------------------------------------------------------
1247 public function encodeModeNum($version)
1248 {
1249 try {
1250
1251 $words = (int)($this->size / 3);
1252 $bs = new QRbitstream();
1253
1254 $val = 0x1;
1255 $bs->appendNum(4, $val);
1256 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size);
1257
1258 for($i=0; $i<$words; $i++) {
1259 $val = (ord($this->data[$i*3 ]) - ord('0')) * 100;
1260 $val += (ord($this->data[$i*3+1]) - ord('0')) * 10;
1261 $val += (ord($this->data[$i*3+2]) - ord('0'));
1262 $bs->appendNum(10, $val);
1263 }
1264
1265 if($this->size - $words * 3 == 1) {
1266 $val = ord($this->data[$words*3]) - ord('0');
1267 $bs->appendNum(4, $val);
1268 } else if($this->size - $words * 3 == 2) {
1269 $val = (ord($this->data[$words*3 ]) - ord('0')) * 10;
1270 $val += (ord($this->data[$words*3+1]) - ord('0'));
1271 $bs->appendNum(7, $val);
1272 }
1273
1274 $this->bstream = $bs;
1275 return 0;
1276
1277 } catch (Exception $e) {
1278 return -1;
1279 }
1280 }
1281
1282 //----------------------------------------------------------------------
1283 public function encodeModeAn($version)
1284 {
1285 try {
1286 $words = (int)($this->size / 2);
1287 $bs = new QRbitstream();
1288
1289 $bs->appendNum(4, 0x02);
1290 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size);
1291
1292 for($i=0; $i<$words; $i++) {
1293 $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45;
1294 $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));
1295
1296 $bs->appendNum(11, $val);
1297 }
1298
1299 if($this->size & 1) {
1300 $val = QRinput::lookAnTable(ord($this->data[$words * 2]));
1301 $bs->appendNum(6, $val);
1302 }
1303
1304 $this->bstream = $bs;
1305 return 0;
1306
1307 } catch (Exception $e) {
1308 return -1;
1309 }
1310 }
1311
1312 //----------------------------------------------------------------------
1313 public function encodeMode8($version)
1314 {
1315 try {
1316 $bs = new QRbitstream();
1317
1318 $bs->appendNum(4, 0x4);
1319 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size);
1320
1321 for($i=0; $i<$this->size; $i++) {
1322 $bs->appendNum(8, ord($this->data[$i]));
1323 }
1324
1325 $this->bstream = $bs;
1326 return 0;
1327
1328 } catch (Exception $e) {
1329 return -1;
1330 }
1331 }
1332
1333 //----------------------------------------------------------------------
1334 public function encodeModeKanji($version)
1335 {
1336 try {
1337
1338 $bs = new QRbitstream();
1339
1340 $bs->appendNum(4, 0x8);
1341 $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2));
1342
1343 for($i=0; $i<$this->size; $i+=2) {
1344 $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]);
1345 if($val <= 0x9ffc) {
1346 $val -= 0x8140;
1347 } else {
1348 $val -= 0xc140;
1349 }
1350
1351 $h = ($val >> 8) * 0xc0;
1352 $val = ($val & 0xff) + $h;
1353
1354 $bs->appendNum(13, $val);
1355 }
1356
1357 $this->bstream = $bs;
1358 return 0;
1359
1360 } catch (Exception $e) {
1361 return -1;
1362 }
1363 }
1364
1365 //----------------------------------------------------------------------
1366 public function encodeModeStructure()
1367 {
1368 try {
1369 $bs = new QRbitstream();
1370
1371 $bs->appendNum(4, 0x03);
1372 $bs->appendNum(4, ord($this->data[1]) - 1);
1373 $bs->appendNum(4, ord($this->data[0]) - 1);
1374 $bs->appendNum(8, ord($this->data[2]));
1375
1376 $this->bstream = $bs;
1377 return 0;
1378
1379 } catch (Exception $e) {
1380 return -1;
1381 }
1382 }
1383
1384 //----------------------------------------------------------------------
1385 public function estimateBitStreamSizeOfEntry($version)
1386 {
1387 $bits = 0;
1388
1389 if($version == 0)
1390 $version = 1;
1391
1392 switch($this->mode) {
1393 case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break;
1394 case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break;
1395 case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break;
1396 case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break;
1397 case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS;
1398 default:
1399 return 0;
1400 }
1401
1402 $l = QRspec::lengthIndicator($this->mode, $version);
1403 $m = 1 << $l;
1404 $num = (int)(($this->size + $m - 1) / $m);
1405
1406 $bits += $num * (4 + $l);
1407
1408 return $bits;
1409 }
1410
1411 //----------------------------------------------------------------------
1412 public function encodeBitStream($version)
1413 {
1414 try {
1415
1416 unset($this->bstream);
1417 $words = QRspec::maximumWords($this->mode, $version);
1418
1419 if($this->size > $words) {
1420
1421 $st1 = new QRinputItem($this->mode, $words, $this->data);
1422 $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words));
1423
1424 $st1->encodeBitStream($version);
1425 $st2->encodeBitStream($version);
1426
1427 $this->bstream = new QRbitstream();
1428 $this->bstream->append($st1->bstream);
1429 $this->bstream->append($st2->bstream);
1430
1431 unset($st1);
1432 unset($st2);
1433
1434 } else {
1435
1436 $ret = 0;
1437
1438 switch($this->mode) {
1439 case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break;
1440 case QR_MODE_AN: $ret = $this->encodeModeAn($version); break;
1441 case QR_MODE_8: $ret = $this->encodeMode8($version); break;
1442 case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break;
1443 case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break;
1444
1445 default:
1446 break;
1447 }
1448
1449 if($ret < 0)
1450 return -1;
1451 }
1452
1453 return $this->bstream->size();
1454
1455 } catch (Exception $e) {
1456 return -1;
1457 }
1458 }
1459 };
1460
1461 //##########################################################################
1462
1463 class QRinput {
1464
1465 public $items;
1466
1467 private $version;
1468 private $level;
1469
1470 //----------------------------------------------------------------------
1471 public function __construct($version = 0, $level = QR_ECLEVEL_L)
1472 {
1473 if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {
1474 throw new Exception('Invalid version no');
1475 return NULL;
1476 }
1477
1478 $this->version = $version;
1479 $this->level = $level;
1480 }
1481
1482 //----------------------------------------------------------------------
1483 public function getVersion()
1484 {
1485 return $this->version;
1486 }
1487
1488 //----------------------------------------------------------------------
1489 public function setVersion($version)
1490 {
1491 if($version < 0 || $version > QRSPEC_VERSION_MAX) {
1492 throw new Exception('Invalid version no');
1493 return -1;
1494 }
1495
1496 $this->version = $version;
1497
1498 return 0;
1499 }
1500
1501 //----------------------------------------------------------------------
1502 public function getErrorCorrectionLevel()
1503 {
1504 return $this->level;
1505 }
1506
1507 //----------------------------------------------------------------------
1508 public function setErrorCorrectionLevel($level)
1509 {
1510 if($level > QR_ECLEVEL_H) {
1511 throw new Exception('Invalid ECLEVEL');
1512 return -1;
1513 }
1514
1515 $this->level = $level;
1516
1517 return 0;
1518 }
1519
1520 //----------------------------------------------------------------------
1521 public function appendEntry(QRinputItem $entry)
1522 {
1523 $this->items[] = $entry;
1524 }
1525
1526 //----------------------------------------------------------------------
1527 public function append($mode, $size, $data)
1528 {
1529 try {
1530 $entry = new QRinputItem($mode, $size, $data);
1531 $this->items[] = $entry;
1532 return 0;
1533 } catch (Exception $e) {
1534 return -1;
1535 }
1536 }
1537
1538 //----------------------------------------------------------------------
1539
1540 public function insertStructuredAppendHeader($size, $index, $parity)
1541 {
1542 if( $size > MAX_STRUCTURED_SYMBOLS ) {
1543 throw new Exception('insertStructuredAppendHeader wrong size');
1544 }
1545
1546 if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
1547 throw new Exception('insertStructuredAppendHeader wrong index');
1548 }
1549
1550 $buf = array($size, $index, $parity);
1551
1552 try {
1553 $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);
1554 array_unshift($this->items, $entry);
1555 return 0;
1556 } catch (Exception $e) {
1557 return -1;
1558 }
1559 }
1560
1561 //----------------------------------------------------------------------
1562 public function calcParity()
1563 {
1564 $parity = 0;
1565
1566 foreach($this->items as $item) {
1567 if($item->mode != QR_MODE_STRUCTURE) {
1568 for($i=$item->size-1; $i>=0; $i--) {
1569 $parity ^= $item->data[$i];
1570 }
1571 }
1572 }
1573
1574 return $parity;
1575 }
1576
1577 //----------------------------------------------------------------------
1578 public static function checkModeNum($size, $data)
1579 {
1580 for($i=0; $i<$size; $i++) {
1581 if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){
1582 return false;
1583 }
1584 }
1585
1586 return true;
1587 }
1588
1589 //----------------------------------------------------------------------
1590 public static function estimateBitsModeNum($size)
1591 {
1592 $w = (int)$size / 3;
1593 $bits = $w * 10;
1594
1595 switch($size - $w * 3) {
1596 case 1:
1597 $bits += 4;
1598 break;
1599 case 2:
1600 $bits += 7;
1601 break;
1602 default:
1603 break;
1604 }
1605
1606 return $bits;
1607 }
1608
1609 //----------------------------------------------------------------------
1610 public static $anTable = array(
1611 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1612 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1613 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
1614 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1,
1615 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1616 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
1617 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1618 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1619 );
1620
1621 //----------------------------------------------------------------------
1622 public static function lookAnTable($c)
1623 {
1624 return (($c > 127)?-1:self::$anTable[$c]);
1625 }
1626
1627 //----------------------------------------------------------------------
1628 public static function checkModeAn($size, $data)
1629 {
1630 for($i=0; $i<$size; $i++) {
1631 if (self::lookAnTable(ord($data[$i])) == -1) {
1632 return false;
1633 }
1634 }
1635
1636 return true;
1637 }
1638
1639 //----------------------------------------------------------------------
1640 public static function estimateBitsModeAn($size)
1641 {
1642 $w = (int)($size / 2);
1643 $bits = $w * 11;
1644
1645 if($size & 1) {
1646 $bits += 6;
1647 }
1648
1649 return $bits;
1650 }
1651
1652 //----------------------------------------------------------------------
1653 public static function estimateBitsMode8($size)
1654 {
1655 return $size * 8;
1656 }
1657
1658 //----------------------------------------------------------------------
1659 public function estimateBitsModeKanji($size)
1660 {
1661 return (int)(($size / 2) * 13);
1662 }
1663
1664 //----------------------------------------------------------------------
1665 public static function checkModeKanji($size, $data)
1666 {
1667 if($size & 1)
1668 return false;
1669
1670 for($i=0; $i<$size; $i+=2) {
1671 $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
1672 if( $val < 0x8140
1673 || ($val > 0x9ffc && $val < 0xe040)
1674 || $val > 0xebbf) {
1675 return false;
1676 }
1677 }
1678
1679 return true;
1680 }
1681
1682 /***********************************************************************
1683 * Validation
1684 **********************************************************************/
1685
1686 public static function check($mode, $size, $data)
1687 {
1688 if($size <= 0)
1689 return false;
1690
1691 switch($mode) {
1692 case QR_MODE_NUM: return self::checkModeNum($size, $data); break;
1693 case QR_MODE_AN: return self::checkModeAn($size, $data); break;
1694 case QR_MODE_KANJI: return self::checkModeKanji($size, $data); break;
1695 case QR_MODE_8: return true; break;
1696 case QR_MODE_STRUCTURE: return true; break;
1697
1698 default:
1699 break;
1700 }
1701
1702 return false;
1703 }
1704
1705
1706 //----------------------------------------------------------------------
1707 public function estimateBitStreamSize($version)
1708 {
1709 $bits = 0;
1710
1711 foreach($this->items as $item) {
1712 $bits += $item->estimateBitStreamSizeOfEntry($version);
1713 }
1714
1715 return $bits;
1716 }
1717
1718 //----------------------------------------------------------------------
1719 public function estimateVersion()
1720 {
1721 $version = 0;
1722 $prev = 0;
1723 do {
1724 $prev = $version;
1725 $bits = $this->estimateBitStreamSize($prev);
1726 $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1727 if ($version < 0) {
1728 return -1;
1729 }
1730 } while ($version > $prev);
1731
1732 return $version;
1733 }
1734
1735 //----------------------------------------------------------------------
1736 public static function lengthOfCode($mode, $version, $bits)
1737 {
1738 $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);
1739 switch($mode) {
1740 case QR_MODE_NUM:
1741 $chunks = (int)($payload / 10);
1742 $remain = $payload - $chunks * 10;
1743 $size = $chunks * 3;
1744 if($remain >= 7) {
1745 $size += 2;
1746 } else if($remain >= 4) {
1747 $size += 1;
1748 }
1749 break;
1750 case QR_MODE_AN:
1751 $chunks = (int)($payload / 11);
1752 $remain = $payload - $chunks * 11;
1753 $size = $chunks * 2;
1754 if($remain >= 6)
1755 $size++;
1756 break;
1757 case QR_MODE_8:
1758 $size = (int)($payload / 8);
1759 break;
1760 case QR_MODE_KANJI:
1761 $size = (int)(($payload / 13) * 2);
1762 break;
1763 case QR_MODE_STRUCTURE:
1764 $size = (int)($payload / 8);
1765 break;
1766 default:
1767 $size = 0;
1768 break;
1769 }
1770
1771 $maxsize = QRspec::maximumWords($mode, $version);
1772 if($size < 0) $size = 0;
1773 if($size > $maxsize) $size = $maxsize;
1774
1775 return $size;
1776 }
1777
1778 //----------------------------------------------------------------------
1779 public function createBitStream()
1780 {
1781 $total = 0;
1782
1783 foreach($this->items as $item) {
1784 $bits = $item->encodeBitStream($this->version);
1785
1786 if($bits < 0)
1787 return -1;
1788
1789 $total += $bits;
1790 }
1791
1792 return $total;
1793 }
1794
1795 //----------------------------------------------------------------------
1796 public function convertData()
1797 {
1798 $ver = $this->estimateVersion();
1799 if($ver > $this->getVersion()) {
1800 $this->setVersion($ver);
1801 }
1802
1803 for(;;) {
1804 $bits = $this->createBitStream();
1805
1806 if($bits < 0)
1807 return -1;
1808
1809 $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1810 if($ver < 0) {
1811 throw new Exception('WRONG VERSION');
1812 return -1;
1813 } else if($ver > $this->getVersion()) {
1814 $this->setVersion($ver);
1815 } else {
1816 break;
1817 }
1818 }
1819
1820 return 0;
1821 }
1822
1823 //----------------------------------------------------------------------
1824 public function appendPaddingBit(&$bstream)
1825 {
1826 $bits = $bstream->size();
1827 $maxwords = QRspec::getDataLength($this->version, $this->level);
1828 $maxbits = $maxwords * 8;
1829
1830 if ($maxbits == $bits) {
1831 return 0;
1832 }
1833
1834 if ($maxbits - $bits < 5) {
1835 return $bstream->appendNum($maxbits - $bits, 0);
1836 }
1837
1838 $bits += 4;
1839 $words = (int)(($bits + 7) / 8);
1840
1841 $padding = new QRbitstream();
1842 $ret = $padding->appendNum($words * 8 - $bits + 4, 0);
1843
1844 if($ret < 0)
1845 return $ret;
1846
1847 $padlen = $maxwords - $words;
1848
1849 if($padlen > 0) {
1850
1851 $padbuf = array();
1852 for($i=0; $i<$padlen; $i++) {
1853 $padbuf[$i] = ($i&1)?0x11:0xec;
1854 }
1855
1856 $ret = $padding->appendBytes($padlen, $padbuf);
1857
1858 if($ret < 0)
1859 return $ret;
1860
1861 }
1862
1863 $ret = $bstream->append($padding);
1864
1865 return $ret;
1866 }
1867
1868 //----------------------------------------------------------------------
1869 public function mergeBitStream()
1870 {
1871 if($this->convertData() < 0) {
1872 return null;
1873 }
1874
1875 $bstream = new QRbitstream();
1876
1877 foreach($this->items as $item) {
1878 $ret = $bstream->append($item->bstream);
1879 if($ret < 0) {
1880 return null;
1881 }
1882 }
1883
1884 return $bstream;
1885 }
1886
1887 //----------------------------------------------------------------------
1888 public function getBitStream()
1889 {
1890
1891 $bstream = $this->mergeBitStream();
1892
1893 if($bstream == null) {
1894 return null;
1895 }
1896
1897 $ret = $this->appendPaddingBit($bstream);
1898 if($ret < 0) {
1899 return null;
1900 }
1901
1902 return $bstream;
1903 }
1904
1905 //----------------------------------------------------------------------
1906 public function getByteStream()
1907 {
1908 $bstream = $this->getBitStream();
1909 if($bstream == null) {
1910 return null;
1911 }
1912
1913 return $bstream->toByte();
1914 }
1915 }
1916
1917 /** @}*/
1918
1919
1920
1921//---- qrbitstream.php -----------------------------
1922
1923
1924
1925
1926/*
1927 * PHP QR Code encoder
1928 *
1929 * Bitstream class
1930 *
1931 * Based on libqrencode C library distributed under LGPL 2.1
1932 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
1933 *
1934 * PHP QR Code is distributed under LGPL 3
1935 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
1936 *
1937 * This library is free software; you can redistribute it and/or
1938 * modify it under the terms of the GNU Lesser General Public
1939 * License as published by the Free Software Foundation; either
1940 * version 3 of the License, or any later version.
1941 *
1942 * This library is distributed in the hope that it will be useful,
1943 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1944 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1945 * Lesser General Public License for more details.
1946 *
1947 * You should have received a copy of the GNU Lesser General Public
1948 * License along with this library; if not, write to the Free Software
1949 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1950 */
1951
1952 /** @addtogroup CoreGroup */
1953 /** @{ */
1954
1955 /**
1956 PHP bit stream.
1957 Class implementing array of bits (= 1 or 0 ints). Allows to initialize and append
1958 bits from given Integer or array of Bytes.
1959 */
1960 class QRbitstream {
1961
1962 /**
1963 Array containing bit data stream
1964 */
1965 public $data = array();
1966
1967 //----------------------------------------------------------------------
1968 /**
1969 @return Integer size of byte stream
1970 */
1971 public function size()
1972 {
1973 return count($this->data);
1974 }
1975
1976 //----------------------------------------------------------------------
1977 /**
1978 Allocates bit stream, fills bit data stream with 0's.
1979 This operation is __destructive__, will replace orginal stream contents!
1980 @param Integer $setLength desired target stream size
1981 @return Integer 0 on success, other on failure
1982 */
1983 public function allocate($setLength)
1984 {
1985 $this->data = array_fill(0, $setLength, 0);
1986 return 0;
1987 }
1988
1989 //----------------------------------------------------------------------
1990 /**
1991 Creates new bit stream from given Integer number.
1992 @param Integer $bits bit count
1993 @param Integer $num integer to convert
1994 @return QRbitstream bit stream object containing first $bits bits from $num in order from LSB to MSB
1995 */
1996 public static function newFromNum($bits, $num)
1997 {
1998 $bstream = new QRbitstream();
1999 $bstream->allocate($bits);
2000
2001 $mask = 1 << ($bits - 1);
2002 for($i=0; $i<$bits; $i++) {
2003 if($num & $mask) {
2004 $bstream->data[$i] = 1;
2005 } else {
2006 $bstream->data[$i] = 0;
2007 }
2008 $mask = $mask >> 1;
2009 }
2010
2011 return $bstream;
2012 }
2013
2014 //----------------------------------------------------------------------
2015 /**
2016 Creates new bit stream from given byte array.
2017 @param Integer $size size of array
2018 @param Array $data array ob bytes
2019 @return QRbitstream bit stream object containing bit contents of given bytes array
2020 */
2021 public static function newFromBytes($size, $data)
2022 {
2023 $bstream = new QRbitstream();
2024 $bstream->allocate($size * 8);
2025 $p=0;
2026
2027 for($i=0; $i<$size; $i++) {
2028 $mask = 0x80;
2029 for($j=0; $j<8; $j++) {
2030 if($data[$i] & $mask) {
2031 $bstream->data[$p] = 1;
2032 } else {
2033 $bstream->data[$p] = 0;
2034 }
2035 $p++;
2036 $mask = $mask >> 1;
2037 }
2038 }
2039
2040 return $bstream;
2041 }
2042
2043 //----------------------------------------------------------------------
2044 /**
2045 Appends given bit stream at end of this stream.
2046 @param QRbitstream $arg bit stream to be appended
2047 @return Integer status of append operation, 0 when success, -1 when $arg is null
2048 */
2049 public function append(QRbitstream $arg)
2050 {
2051 if (is_null($arg)) {
2052 return -1;
2053 }
2054
2055 if($arg->size() == 0) {
2056 return 0;
2057 }
2058
2059 if($this->size() == 0) {
2060 $this->data = $arg->data;
2061 return 0;
2062 }
2063
2064 $this->data = array_values(array_merge($this->data, $arg->data));
2065
2066 return 0;
2067 }
2068
2069 //----------------------------------------------------------------------
2070 /**
2071 Appends bit stream cteated from given Integer number at end of current stream.
2072 @param Integer $bits bit count
2073 @param Integer $num integer to convert
2074 @return Integer status of append operation, status of append operation, 0 when success, -1 otherwise
2075 */
2076 public function appendNum($bits, $num)
2077 {
2078 if ($bits == 0)
2079 return 0;
2080
2081 $b = QRbitstream::newFromNum($bits, $num);
2082
2083 if(is_null($b))
2084 return -1;
2085
2086 $ret = $this->append($b);
2087 unset($b);
2088
2089 return $ret;
2090 }
2091
2092 //----------------------------------------------------------------------
2093 /**
2094 Appends bit stream created from from given byte array at end of current stream.
2095 @param Integer $size size of array
2096 @param Array $data array ob bytes
2097 @return Integer status of append operation, status of append operation, 0 when success, -1 otherwise
2098 */
2099 public function appendBytes($size, $data)
2100 {
2101 if ($size == 0)
2102 return 0;
2103
2104 $b = QRbitstream::newFromBytes($size, $data);
2105
2106 if(is_null($b))
2107 return -1;
2108
2109 $ret = $this->append($b);
2110 unset($b);
2111
2112 return $ret;
2113 }
2114
2115 //----------------------------------------------------------------------
2116 /**
2117 Converts current bit stream into byte array.
2118 @returns Array array of bytes
2119 */
2120 public function toByte()
2121 {
2122
2123 $size = $this->size();
2124
2125 if($size == 0) {
2126 return array();
2127 }
2128
2129 $data = array_fill(0, (int)(($size + 7) / 8), 0);
2130 $bytes = (int)($size / 8);
2131
2132 $p = 0;
2133
2134 for($i=0; $i<$bytes; $i++) {
2135 $v = 0;
2136 for($j=0; $j<8; $j++) {
2137 $v = $v << 1;
2138 $v |= $this->data[$p];
2139 $p++;
2140 }
2141 $data[$i] = $v;
2142 }
2143
2144 if($size & 7) {
2145 $v = 0;
2146 for($j=0; $j<($size & 7); $j++) {
2147 $v = $v << 1;
2148 $v |= $this->data[$p];
2149 $p++;
2150 }
2151 $data[$bytes] = $v;
2152 }
2153
2154 return $data;
2155 }
2156
2157 }
2158
2159 /** @}*/
2160
2161
2162
2163//---- qrsplit.php -----------------------------
2164
2165
2166
2167
2168/*
2169 * PHP QR Code encoder
2170 *
2171 * Input splitting classes
2172 *
2173 * Based on libqrencode C library distributed under LGPL 2.1
2174 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
2175 *
2176 * PHP QR Code is distributed under LGPL 3
2177 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
2178 *
2179 * The following data / specifications are taken from
2180 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
2181 * or
2182 * "Automatic identification and data capture techniques --
2183 * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
2184 *
2185 * This library is free software; you can redistribute it and/or
2186 * modify it under the terms of the GNU Lesser General Public
2187 * License as published by the Free Software Foundation; either
2188 * version 3 of the License, or any later version.
2189 *
2190 * This library is distributed in the hope that it will be useful,
2191 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2192 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2193 * Lesser General Public License for more details.
2194 *
2195 * You should have received a copy of the GNU Lesser General Public
2196 * License along with this library; if not, write to the Free Software
2197 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2198 */
2199
2200 /** @addtogroup CoreGroup */
2201 /** @{ */
2202
2203 /** Input stream splitter. */
2204 class QRsplit {
2205
2206 public $dataStr = '';
2207 public $input;
2208 public $modeHint;
2209
2210 //----------------------------------------------------------------------
2211 public function __construct($dataStr, $input, $modeHint)
2212 {
2213 $this->dataStr = $dataStr;
2214 $this->input = $input;
2215 $this->modeHint = $modeHint;
2216 }
2217
2218 //----------------------------------------------------------------------
2219 public static function isdigitat($str, $pos)
2220 {
2221 if ($pos >= strlen($str))
2222 return false;
2223
2224 return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
2225 }
2226
2227 //----------------------------------------------------------------------
2228 public static function isalnumat($str, $pos)
2229 {
2230 if ($pos >= strlen($str))
2231 return false;
2232
2233 return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
2234 }
2235
2236 //----------------------------------------------------------------------
2237 public function identifyMode($pos)
2238 {
2239 if ($pos >= strlen($this->dataStr))
2240 return QR_MODE_NUL;
2241
2242 $c = $this->dataStr[$pos];
2243
2244 if(self::isdigitat($this->dataStr, $pos)) {
2245 return QR_MODE_NUM;
2246 } else if(self::isalnumat($this->dataStr, $pos)) {
2247 return QR_MODE_AN;
2248 } else if($this->modeHint == QR_MODE_KANJI) {
2249
2250 if ($pos+1 < strlen($this->dataStr))
2251 {
2252 $d = $this->dataStr[$pos+1];
2253 $word = (ord($c) << 8) | ord($d);
2254 if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
2255 return QR_MODE_KANJI;
2256 }
2257 }
2258 }
2259
2260 return QR_MODE_8;
2261 }
2262
2263 //----------------------------------------------------------------------
2264 public function eatNum()
2265 {
2266 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
2267
2268 $p = 0;
2269 while(self::isdigitat($this->dataStr, $p)) {
2270 $p++;
2271 }
2272
2273 $run = $p;
2274 $mode = $this->identifyMode($p);
2275
2276 if($mode == QR_MODE_8) {
2277 $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
2278 + QRinput::estimateBitsMode8(1) // + 4 + l8
2279 - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
2280 if($dif > 0) {
2281 return $this->eat8();
2282 }
2283 }
2284 if($mode == QR_MODE_AN) {
2285 $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
2286 + QRinput::estimateBitsModeAn(1) // + 4 + la
2287 - QRinput::estimateBitsModeAn($run + 1);// - 4 - la
2288 if($dif > 0) {
2289 return $this->eatAn();
2290 }
2291 }
2292
2293 $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
2294 if($ret < 0)
2295 return -1;
2296
2297 return $run;
2298 }
2299
2300 //----------------------------------------------------------------------
2301 public function eatAn()
2302 {
2303 $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
2304 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
2305
2306 $p = 0;
2307
2308 while(self::isalnumat($this->dataStr, $p)) {
2309 if(self::isdigitat($this->dataStr, $p)) {
2310 $q = $p;
2311 while(self::isdigitat($this->dataStr, $q)) {
2312 $q++;
2313 }
2314
2315 $dif = QRinput::estimateBitsModeAn($p) // + 4 + la
2316 + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
2317 - QRinput::estimateBitsModeAn($q); // - 4 - la
2318
2319 if($dif < 0) {
2320 break;
2321 } else {
2322 $p = $q;
2323 }
2324 } else {
2325 $p++;
2326 }
2327 }
2328
2329 $run = $p;
2330
2331 if(!self::isalnumat($this->dataStr, $p)) {
2332 $dif = QRinput::estimateBitsModeAn($run) + 4 + $la
2333 + QRinput::estimateBitsMode8(1) // + 4 + l8
2334 - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
2335 if($dif > 0) {
2336 return $this->eat8();
2337 }
2338 }
2339
2340 $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
2341 if($ret < 0)
2342 return -1;
2343
2344 return $run;
2345 }
2346
2347 //----------------------------------------------------------------------
2348 public function eatKanji()
2349 {
2350 $p = 0;
2351
2352 while($this->identifyMode($p) == QR_MODE_KANJI) {
2353 $p += 2;
2354 }
2355
2356 $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
2357 if($ret < 0)
2358 return -1;
2359
2360 return $run;
2361 }
2362
2363 //----------------------------------------------------------------------
2364 public function eat8()
2365 {
2366 $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
2367 $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
2368
2369 $p = 1;
2370 $dataStrLen = strlen($this->dataStr);
2371
2372 while($p < $dataStrLen) {
2373
2374 $mode = $this->identifyMode($p);
2375 if($mode == QR_MODE_KANJI) {
2376 break;
2377 }
2378 if($mode == QR_MODE_NUM) {
2379 $q = $p;
2380 while(self::isdigitat($this->dataStr, $q)) {
2381 $q++;
2382 }
2383 $dif = QRinput::estimateBitsMode8($p) // + 4 + l8
2384 + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
2385 - QRinput::estimateBitsMode8($q); // - 4 - l8
2386 if($dif < 0) {
2387 break;
2388 } else {
2389 $p = $q;
2390 }
2391 } else if($mode == QR_MODE_AN) {
2392 $q = $p;
2393 while(self::isalnumat($this->dataStr, $q)) {
2394 $q++;
2395 }
2396 $dif = QRinput::estimateBitsMode8($p) // + 4 + l8
2397 + QRinput::estimateBitsModeAn($q - $p) + 4 + $la
2398 - QRinput::estimateBitsMode8($q); // - 4 - l8
2399 if($dif < 0) {
2400 break;
2401 } else {
2402 $p = $q;
2403 }
2404 } else {
2405 $p++;
2406 }
2407 }
2408
2409 $run = $p;
2410 $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
2411
2412 if($ret < 0)
2413 return -1;
2414
2415 return $run;
2416 }
2417
2418 //----------------------------------------------------------------------
2419 public function splitString()
2420 {
2421 while (strlen($this->dataStr) > 0)
2422 {
2423 if($this->dataStr == '')
2424 return 0;
2425
2426 $mode = $this->identifyMode(0);
2427
2428 switch ($mode) {
2429 case QR_MODE_NUM: $length = $this->eatNum(); break;
2430 case QR_MODE_AN: $length = $this->eatAn(); break;
2431 case QR_MODE_KANJI:
2432 if ($hint == QR_MODE_KANJI)
2433 $length = $this->eatKanji();
2434 else $length = $this->eat8();
2435 break;
2436 default: $length = $this->eat8(); break;
2437
2438 }
2439
2440 if($length == 0) return 0;
2441 if($length < 0) return -1;
2442
2443 $this->dataStr = substr($this->dataStr, $length);
2444 }
2445 }
2446
2447 //----------------------------------------------------------------------
2448 public function toUpper()
2449 {
2450 $stringLen = strlen($this->dataStr);
2451 $p = 0;
2452
2453 while ($p<$stringLen) {
2454 $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint);
2455 if($mode == QR_MODE_KANJI) {
2456 $p += 2;
2457 } else {
2458 if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {
2459 $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
2460 }
2461 $p++;
2462 }
2463 }
2464
2465 return $this->dataStr;
2466 }
2467
2468 //----------------------------------------------------------------------
2469 public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
2470 {
2471 if(is_null($string) || $string == '\0' || $string == '') {
2472 throw new Exception('empty string!!!');
2473 }
2474
2475 $split = new QRsplit($string, $input, $modeHint);
2476
2477 if(!$casesensitive)
2478 $split->toUpper();
2479
2480 return $split->splitString();
2481 }
2482 }
2483
2484 /** @} */
2485
2486
2487
2488//---- qrrscode.php -----------------------------
2489
2490
2491
2492
2493/*
2494 * PHP QR Code encoder
2495 *
2496 * Reed-Solomon error correction support
2497 *
2498 * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
2499 * (libfec is released under the GNU Lesser General Public License.)
2500 *
2501 * Based on libqrencode C library distributed under LGPL 2.1
2502 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
2503 *
2504 * PHP QR Code is distributed under LGPL 3
2505 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
2506 *
2507 * This library is free software; you can redistribute it and/or
2508 * modify it under the terms of the GNU Lesser General Public
2509 * License as published by the Free Software Foundation; either
2510 * version 3 of the License, or any later version.
2511 *
2512 * This library is distributed in the hope that it will be useful,
2513 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2514 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2515 * Lesser General Public License for more details.
2516 *
2517 * You should have received a copy of the GNU Lesser General Public
2518 * License along with this library; if not, write to the Free Software
2519 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2520 */
2521
2522 /** @addtogroup CoreGroup */
2523 /** @{ */
2524
2525 /** Reed-Solomon encoder item */
2526 class QRrsItem {
2527
2528 /** Bits per symbol */
2529 public $mm;
2530 /** Symbols per block (= (1<<mm)-1) */
2531 public $nn;
2532 /** Log lookup table */
2533 public $alpha_to = array();
2534 /** Antilog lookup table */
2535 public $index_of = array();
2536 /** Generator polynomial */
2537 public $genpoly = array();
2538 /** Number of generator roots = number of parity symbols */
2539 public $nroots;
2540 /** First consecutive root, index form */
2541 public $fcr;
2542 /** Primitive element, index form */
2543 public $prim;
2544 /** Prim-th root of 1, index form */
2545 public $iprim;
2546 /** Padding bytes in shortened block */
2547 public $pad;
2548 /** Galois Field Polynomial */
2549 public $gfpoly;
2550
2551 //----------------------------------------------------------------------
2552 /** Modulo function in defined Field
2553 @param Integer $x number to be modulo-mapped
2554 */
2555 public function modnn($x)
2556 {
2557 while ($x >= $this->nn) {
2558 $x -= $this->nn;
2559 $x = ($x >> $this->mm) + ($x & $this->nn);
2560 }
2561
2562 return $x;
2563 }
2564
2565 //----------------------------------------------------------------------
2566 /** Encoder initialisation
2567 @param Integer $symsize symbol size, bit count (1..8)
2568 @param Integer $gfpoly Galois Field Polynomial
2569 @param Integer $fcr First consecutive root
2570 @param Integer $prim Primitive element
2571 @param Integer $nroots Number of generator roots = number of parity symbols
2572 @param Integer $pad Padding bytes in shortened block
2573 */
2574 public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
2575 {
2576 // Common code for intializing a Reed-Solomon control block (char or int symbols)
2577 // Copyright 2004 Phil Karn, KA9Q
2578 // May be used under the terms of the GNU Lesser General Public License (LGPL)
2579
2580 $rs = null;
2581
2582 // Check parameter ranges
2583 if($symsize < 0 || $symsize > 8) return $rs;
2584 if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs;
2585 if($prim <= 0 || $prim >= (1<<$symsize)) return $rs;
2586 if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values!
2587 if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding
2588
2589 $rs = new QRrsItem();
2590 $rs->mm = $symsize;
2591 $rs->nn = (1<<$symsize)-1;
2592 $rs->pad = $pad;
2593
2594 $rs->alpha_to = array_fill(0, $rs->nn+1, 0);
2595 $rs->index_of = array_fill(0, $rs->nn+1, 0);
2596
2597 // PHP style macro replacement ;)
2598 $NN =& $rs->nn;
2599 $A0 =& $NN;
2600
2601 // Generate Galois field lookup tables
2602 $rs->index_of[0] = $A0; // log(zero) = -inf
2603 $rs->alpha_to[$A0] = 0; // alpha**-inf = 0
2604 $sr = 1;
2605
2606 for($i=0; $i<$rs->nn; $i++) {
2607 $rs->index_of[$sr] = $i;
2608 $rs->alpha_to[$i] = $sr;
2609 $sr <<= 1;
2610 if($sr & (1<<$symsize)) {
2611 $sr ^= $gfpoly;
2612 }
2613 $sr &= $rs->nn;
2614 }
2615
2616 if($sr != 1){
2617 // field generator polynomial is not primitive!
2618 $rs = NULL;
2619 return $rs;
2620 }
2621
2622 /* Form RS code generator polynomial from its roots */
2623 $rs->genpoly = array_fill(0, $nroots+1, 0);
2624
2625 $rs->fcr = $fcr;
2626 $rs->prim = $prim;
2627 $rs->nroots = $nroots;
2628 $rs->gfpoly = $gfpoly;
2629
2630 /* Find prim-th root of 1, used in decoding */
2631 for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn)
2632 ; // intentional empty-body loop!
2633
2634 $rs->iprim = (int)($iprim / $prim);
2635 $rs->genpoly[0] = 1;
2636
2637 for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
2638 $rs->genpoly[$i+1] = 1;
2639
2640 // Multiply rs->genpoly[] by @**(root + x)
2641 for ($j = $i; $j > 0; $j--) {
2642 if ($rs->genpoly[$j] != 0) {
2643 $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];
2644 } else {
2645 $rs->genpoly[$j] = $rs->genpoly[$j-1];
2646 }
2647 }
2648 // rs->genpoly[0] can never be zero
2649 $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];
2650 }
2651
2652 // convert rs->genpoly[] to index form for quicker encoding
2653 for ($i = 0; $i <= $nroots; $i++)
2654 $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
2655
2656 return $rs;
2657 }
2658
2659 //----------------------------------------------------------------------
2660 /** Appends char into encoder
2661 @param String input
2662 @param Array parity table
2663 */
2664 public function encode_rs_char($data, &$parity)
2665 {
2666 $MM =& $this->mm;
2667 $NN =& $this->nn;
2668 $ALPHA_TO =& $this->alpha_to;
2669 $INDEX_OF =& $this->index_of;
2670 $GENPOLY =& $this->genpoly;
2671 $NROOTS =& $this->nroots;
2672 $FCR =& $this->fcr;
2673 $PRIM =& $this->prim;
2674 $IPRIM =& $this->iprim;
2675 $PAD =& $this->pad;
2676 $A0 =& $NN;
2677
2678 $parity = array_fill(0, $NROOTS, 0);
2679
2680 for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) {
2681
2682 $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2683 if($feedback != $A0) {
2684 // feedback term is non-zero
2685
2686 // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2687 // always be for the polynomials constructed by init_rs()
2688 $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);
2689
2690 for($j=1;$j<$NROOTS;$j++) {
2691 $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])];
2692 }
2693 }
2694
2695 // Shift
2696 array_shift($parity);
2697 if($feedback != $A0) {
2698 array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);
2699 } else {
2700 array_push($parity, 0);
2701 }
2702 }
2703 }
2704 }
2705
2706 //##########################################################################
2707 /** Reed-Solomon encoder */
2708 class QRrs {
2709
2710 /** Encoder items array */
2711 public static $items = array();
2712
2713 //----------------------------------------------------------------------
2714 /** Encoder initialisation
2715 @param Integer $symsize symbol size, bit count (1..8)
2716 @param Integer $gfpoly Galois Field Polynomial
2717 @param Integer $fcr First consecutive root
2718 @param Integer $prim Primitive element
2719 @param Integer $nroots Number of generator roots = number of parity symbols
2720 @param Integer $pad Padding bytes in shortened block
2721 */
2722 public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
2723 {
2724 foreach(self::$items as $rs) {
2725 if($rs->pad != $pad) continue;
2726 if($rs->nroots != $nroots) continue;
2727 if($rs->mm != $symsize) continue;
2728 if($rs->gfpoly != $gfpoly) continue;
2729 if($rs->fcr != $fcr) continue;
2730 if($rs->prim != $prim) continue;
2731
2732 return $rs;
2733 }
2734
2735 $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2736 array_unshift(self::$items, $rs);
2737
2738 return $rs;
2739 }
2740 }
2741
2742 /** @}*/
2743
2744
2745
2746//---- qrmask.php -----------------------------
2747
2748
2749
2750
2751/*
2752 * PHP QR Code encoder
2753 *
2754 * Masking
2755 *
2756 * Based on libqrencode C library distributed under LGPL 2.1
2757 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
2758 *
2759 * PHP QR Code is distributed under LGPL 3
2760 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
2761 *
2762 * This library is free software; you can redistribute it and/or
2763 * modify it under the terms of the GNU Lesser General Public
2764 * License as published by the Free Software Foundation; either
2765 * version 3 of the License, or any later version.
2766 *
2767 * This library is distributed in the hope that it will be useful,
2768 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2769 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2770 * Lesser General Public License for more details.
2771 *
2772 * You should have received a copy of the GNU Lesser General Public
2773 * License along with this library; if not, write to the Free Software
2774 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2775 */
2776
2777
2778
2779 define('N1', 3);
2780 define('N2', 3);
2781 define('N3', 40);
2782 define('N4', 10);
2783
2784 /** @addtogroup CoreGroup */
2785 /** @{ */
2786
2787 class QRmask {
2788
2789 public $runLength = array();
2790
2791 //----------------------------------------------------------------------
2792 public function __construct()
2793 {
2794 $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
2795 }
2796
2797 //----------------------------------------------------------------------
2798 public function writeFormatInformation($width, &$frame, $mask, $level)
2799 {
2800 $blacks = 0;
2801 $format = QRspec::getFormatInfo($mask, $level);
2802
2803 for($i=0; $i<8; $i++) {
2804 if($format & 1) {
2805 $blacks += 2;
2806 $v = 0x85;
2807 } else {
2808 $v = 0x84;
2809 }
2810
2811 $frame[8][$width - 1 - $i] = chr($v);
2812 if($i < 6) {
2813 $frame[$i][8] = chr($v);
2814 } else {
2815 $frame[$i + 1][8] = chr($v);
2816 }
2817 $format = $format >> 1;
2818 }
2819
2820 for($i=0; $i<7; $i++) {
2821 if($format & 1) {
2822 $blacks += 2;
2823 $v = 0x85;
2824 } else {
2825 $v = 0x84;
2826 }
2827
2828 $frame[$width - 7 + $i][8] = chr($v);
2829 if($i == 0) {
2830 $frame[8][7] = chr($v);
2831 } else {
2832 $frame[8][6 - $i] = chr($v);
2833 }
2834
2835 $format = $format >> 1;
2836 }
2837
2838 return $blacks;
2839 }
2840
2841 //----------------------------------------------------------------------
2842 public function mask0($x, $y) { return ($x+$y)&1; }
2843 public function mask1($x, $y) { return ($y&1); }
2844 public function mask2($x, $y) { return ($x%3); }
2845 public function mask3($x, $y) { return ($x+$y)%3; }
2846 public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }
2847 public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; }
2848 public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; }
2849 public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; }
2850
2851 //----------------------------------------------------------------------
2852 private function generateMaskNo($maskNo, $width, $frame)
2853 {
2854 $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
2855
2856 for($y=0; $y<$width; $y++) {
2857 for($x=0; $x<$width; $x++) {
2858 if(ord($frame[$y][$x]) & 0x80) {
2859 $bitMask[$y][$x] = 0;
2860 } else {
2861 $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
2862 $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
2863 }
2864
2865 }
2866 }
2867
2868 return $bitMask;
2869 }
2870
2871 //----------------------------------------------------------------------
2872 public static function serial($bitFrame)
2873 {
2874 $codeArr = array();
2875
2876 foreach ($bitFrame as $line)
2877 $codeArr[] = join('', $line);
2878
2879 return gzcompress(join("\n", $codeArr), 9);
2880 }
2881
2882 //----------------------------------------------------------------------
2883 public static function unserial($code)
2884 {
2885 $codeArr = array();
2886
2887 $codeLines = explode("\n", gzuncompress($code));
2888 foreach ($codeLines as $line)
2889 $codeArr[] = str_split($line);
2890
2891 return $codeArr;
2892 }
2893
2894 //----------------------------------------------------------------------
2895 public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false)
2896 {
2897 $b = 0;
2898 $bitMask = array();
2899
2900 $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
2901
2902 if (QR_CACHEABLE) {
2903 if (file_exists($fileName)) {
2904 $bitMask = self::unserial(file_get_contents($fileName));
2905 } else {
2906 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
2907 if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
2908 mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
2909 file_put_contents($fileName, self::serial($bitMask));
2910 }
2911 } else {
2912 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
2913 }
2914
2915 if ($maskGenOnly)
2916 return;
2917
2918 $d = $s;
2919
2920 for($y=0; $y<$width; $y++) {
2921 for($x=0; $x<$width; $x++) {
2922 if($bitMask[$y][$x] == 1) {
2923 $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
2924 }
2925 $b += (int)(ord($d[$y][$x]) & 1);
2926 }
2927 }
2928
2929 return $b;
2930 }
2931
2932 //----------------------------------------------------------------------
2933 public function makeMask($width, $frame, $maskNo, $level)
2934 {
2935 $masked = array_fill(0, $width, str_repeat("\0", $width));
2936 $this->makeMaskNo($maskNo, $width, $frame, $masked);
2937 $this->writeFormatInformation($width, $masked, $maskNo, $level);
2938
2939 return $masked;
2940 }
2941
2942 //----------------------------------------------------------------------
2943 public function calcN1N3($length)
2944 {
2945 $demerit = 0;
2946
2947 for($i=0; $i<$length; $i++) {
2948
2949 if($this->runLength[$i] >= 5) {
2950 $demerit += (N1 + ($this->runLength[$i] - 5));
2951 }
2952 if($i & 1) {
2953 if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {
2954 $fact = (int)($this->runLength[$i] / 3);
2955 if(($this->runLength[$i-2] == $fact) &&
2956 ($this->runLength[$i-1] == $fact) &&
2957 ($this->runLength[$i+1] == $fact) &&
2958 ($this->runLength[$i+2] == $fact)) {
2959 if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {
2960 $demerit += N3;
2961 } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {
2962 $demerit += N3;
2963 }
2964 }
2965 }
2966 }
2967 }
2968 return $demerit;
2969 }
2970
2971 //----------------------------------------------------------------------
2972 public function evaluateSymbol($width, $frame)
2973 {
2974 $head = 0;
2975 $demerit = 0;
2976
2977 for($y=0; $y<$width; $y++) {
2978 $head = 0;
2979 $this->runLength[0] = 1;
2980
2981 $frameY = $frame[$y];
2982
2983 if ($y>0)
2984 $frameYM = $frame[$y-1];
2985
2986 for($x=0; $x<$width; $x++) {
2987 if(($x > 0) && ($y > 0)) {
2988 $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
2989 $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
2990
2991 if(($b22 | ($w22 ^ 1))&1) {
2992 $demerit += N2;
2993 }
2994 }
2995 if(($x == 0) && (ord($frameY[$x]) & 1)) {
2996 $this->runLength[0] = -1;
2997 $head = 1;
2998 $this->runLength[$head] = 1;
2999 } else if($x > 0) {
3000 if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
3001 $head++;
3002 $this->runLength[$head] = 1;
3003 } else {
3004 $this->runLength[$head]++;
3005 }
3006 }
3007 }
3008
3009 $demerit += $this->calcN1N3($head+1);
3010 }
3011
3012 for($x=0; $x<$width; $x++) {
3013 $head = 0;
3014 $this->runLength[0] = 1;
3015
3016 for($y=0; $y<$width; $y++) {
3017 if($y == 0 && (ord($frame[$y][$x]) & 1)) {
3018 $this->runLength[0] = -1;
3019 $head = 1;
3020 $this->runLength[$head] = 1;
3021 } else if($y > 0) {
3022 if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
3023 $head++;
3024 $this->runLength[$head] = 1;
3025 } else {
3026 $this->runLength[$head]++;
3027 }
3028 }
3029 }
3030
3031 $demerit += $this->calcN1N3($head+1);
3032 }
3033
3034 return $demerit;
3035 }
3036
3037
3038 //----------------------------------------------------------------------
3039 public function mask($width, $frame, $level)
3040 {
3041 $minDemerit = PHP_INT_MAX;
3042 $bestMaskNum = 0;
3043 $bestMask = array();
3044
3045 $checked_masks = array(0,1,2,3,4,5,6,7);
3046
3047 if (QR_FIND_FROM_RANDOM !== false) {
3048
3049 $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);
3050 for ($i = 0; $i < $howManuOut; $i++) {
3051 $remPos = rand (0, count($checked_masks)-1);
3052 unset($checked_masks[$remPos]);
3053 $checked_masks = array_values($checked_masks);
3054 }
3055
3056 }
3057
3058 $bestMask = $frame;
3059
3060 foreach($checked_masks as $i) {
3061 $mask = array_fill(0, $width, str_repeat("\0", $width));
3062
3063 $demerit = 0;
3064 $blacks = 0;
3065 $blacks = $this->makeMaskNo($i, $width, $frame, $mask);
3066 $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
3067 $blacks = (int)(100 * $blacks / ($width * $width));
3068 $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
3069 $demerit += $this->evaluateSymbol($width, $mask);
3070
3071 if($demerit < $minDemerit) {
3072 $minDemerit = $demerit;
3073 $bestMask = $mask;
3074 $bestMaskNum = $i;
3075 }
3076 }
3077
3078 return $bestMask;
3079 }
3080
3081 //----------------------------------------------------------------------
3082 }
3083
3084 /** @}*/
3085
3086
3087
3088//---- qrarea.php -----------------------------
3089
3090
3091
3092
3093/*
3094 * PHP QR Code encoder
3095 *
3096 * Area finding for SVG and CANVAS output
3097 *
3098 * Based on libqrencode C library distributed under LGPL 2.1
3099 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
3100 *
3101 * PHP QR Code is distributed under LGPL 3
3102 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
3103 *
3104 * This library is free software; you can redistribute it and/or
3105 * modify it under the terms of the GNU Lesser General Public
3106 * License as published by the Free Software Foundation; either
3107 * version 3 of the License, or any later version.
3108 *
3109 * This library is distributed in the hope that it will be useful,
3110 * but WITHOUT ANY WARRANTY; without even the implied warranty of
3111 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3112 * Lesser General Public License for more details.
3113 *
3114 * You should have received a copy of the GNU Lesser General Public
3115 * License along with this library; if not, write to the Free Software
3116 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3117 */
3118
3119 // N
3120 // W E
3121 // S
3122
3123 define('QR_AREA_N', 0);
3124 define('QR_AREA_E', 1);
3125 define('QR_AREA_S', 2);
3126 define('QR_AREA_W', 3);
3127
3128 define('QR_AREA_X', 0);
3129 define('QR_AREA_Y', 1);
3130
3131 define('QR_AREA_TRACKER', 0);
3132 define('QR_AREA_PATH', 1);
3133 define('QR_AREA_POINT', 2);
3134 define('QR_AREA_RECT', 3);
3135 define('QR_AREA_LSHAPE', 4);
3136
3137 /** @addtogroup OutputGroup */
3138 /** @{ */
3139
3140 class QRareaGroup {
3141 public $total = 0;
3142 public $vertical = false;
3143 public $horizontal = false;
3144 public $points = array();
3145 public $id = 0;
3146 public $paths = array();
3147
3148 //----------------------------------------------------------------------
3149 public function __construct($selfId, $sx, $sy)
3150 {
3151 $this->total = 1;
3152 $this->points = array(array($sx,$sy,false));
3153 $this->id = $selfId;
3154 }
3155
3156 }
3157
3158 //##########################################################################
3159
3160 class QRarea {
3161
3162 public $width = 0;
3163 private $tab = array();
3164 private $tab_edges = array();
3165 private $groups = array();
3166 private $curr_group = 0;
3167 public $paths = array();
3168
3169
3170 //----------------------------------------------------------------------
3171 public function __construct($source_tab)
3172 {
3173 $py = 0;
3174 $this->width = count($source_tab);
3175 $this->tab = array();
3176 $this->tab_edges = array();
3177 $this->paths = array();
3178
3179 foreach ($source_tab as $line) {
3180 $arr = array();
3181 $arr_edge = array();
3182 $px=0;
3183
3184 foreach (str_split($line) as $item) {
3185
3186 if ($py<7 && $px<7)
3187 $item = 0;
3188
3189 if ($py<7 && $px>=($this->width-7))
3190 $item = 0;
3191
3192 if ($py>=($this->width-7) && $px<7)
3193 $item = 0;
3194
3195 $arr[] = (int)$item;
3196 $arr_edge[] = array(false, false, false, false);
3197
3198 $px++;
3199 }
3200
3201 $this->tab[] = $arr;
3202 $this->tab_edges[] = $arr_edge;
3203 $py++;
3204 }
3205
3206 $this->paths[] = array(QR_AREA_TRACKER, 0,0);
3207 $this->paths[] = array(QR_AREA_TRACKER, 0,($this->width-7));
3208 $this->paths[] = array(QR_AREA_TRACKER, ($this->width-7),0);
3209
3210 $this->groups = array();
3211 $this->curr_group = 1;
3212 }
3213
3214 //----------------------------------------------------------------------
3215 public function getGroups()
3216 {
3217 return $this->groups;
3218 }
3219
3220 //----------------------------------------------------------------------
3221 public function getPaths()
3222 {
3223 return $this->paths;
3224 }
3225
3226 //----------------------------------------------------------------------
3227 public function getWidth()
3228 {
3229 return $this->width;
3230 }
3231
3232 //----------------------------------------------------------------------
3233 public function dumpTab()
3234 {
3235 echo "<style>";
3236 echo "td { height: 2.5em; color: black; font-size: 8px;
3237 border-top: 1px solid silver; border-left: 1px solid silver }";
3238 echo "table { border-bottom: 1px solid silver; border-right: 1px solid silver }";
3239 echo "</style>";
3240 echo "<table border=0 cellpadding=0 cellspacing=0>";
3241
3242 $colorTab = array();
3243
3244 foreach($this->tab as $line) {
3245 foreach($line as $item) {
3246 if (!isset($colorTab[$item])) {
3247 $colorTab[$item] = 'hsl('.mt_rand(0, 360).', '.floor((mt_rand(0, 25))+75).'%, 50%)';
3248 }
3249 }
3250 }
3251
3252 foreach($this->tab as $line) {
3253 echo "<tr>";
3254 foreach($line as $item) {
3255 if ($item == 0) {
3256 echo "<td> </td>";
3257 } else {
3258 echo "<td style='text-align:center;width: 4em;background:".$colorTab[$item]."'>".$item."</td>";
3259 }
3260 }
3261 echo "</tr>";
3262 }
3263 echo "</table>";
3264 }
3265
3266 //----------------------------------------------------------------------
3267 public function dumpEdges()
3268 {
3269 $style_off = '1px dotted silver;';
3270 $style_on = '3px solid red;';
3271
3272 $colorAlloc = array();
3273
3274 echo "<table border='0'>";
3275 $py = 0;
3276 foreach($this->tab_edges as $line) {
3277 $px = 0;
3278 echo "<tr>";
3279 foreach($line as $item) {
3280
3281 $styles = 'border-top:';
3282 if ($item[QR_AREA_N])
3283 $styles .= $style_on;
3284 else $styles .= $style_off;
3285
3286 $styles .= 'border-bottom:';
3287 if ($item[QR_AREA_S])
3288 $styles .= $style_on;
3289 else $styles .= $style_off;
3290
3291 $styles .= 'border-right:';
3292 if ($item[QR_AREA_E])
3293 $styles .= $style_on;
3294 else $styles .= $style_off;
3295
3296 $styles .= 'border-left:';
3297 if ($item[QR_AREA_W])
3298 $styles .= $style_on;
3299 else $styles .= $style_off;
3300
3301 $color = '';
3302 $grp = $this->tab[$py][$px];
3303
3304 if ($grp>0) {
3305 if (!isset($colorAlloc[$grp])) {
3306 $colorAlloc[$grp] = 'hsl('.mt_rand(0, 360).', '.floor((mt_rand(0, 25))+75).'%, 50%)';
3307 }
3308
3309 $color = 'background:'.$colorAlloc[$grp];
3310 }
3311
3312 if ($grp == 0)
3313 $grp = ' ';
3314
3315 echo "<td style='text-align:center;width:1.5em;".$styles.$color."'>".$grp."</td>";
3316 $px++;
3317 }
3318 echo "</tr>";
3319 $py++;
3320 }
3321 echo "</table>";
3322 }
3323
3324 //----------------------------------------------------------------------
3325 private static function rle(&$stringData)
3326 {
3327 $outArray = array();
3328 $symbolArray = str_split($stringData);
3329 $last = '';
3330 $run = 1;
3331
3332 while (count($symbolArray) > 0) {
3333 $symbol = array_shift($symbolArray);
3334
3335 if ($symbol != $last) {
3336 if ($run > 1)
3337 $outArray[] = $run;
3338
3339 if ($last != '')
3340 $outArray[] = $last;
3341
3342 $run = 1;
3343 $last = $symbol;
3344 } else {
3345 $run++;
3346 }
3347 }
3348
3349 if ($run > 1)
3350 $outArray[] = $run;
3351
3352 $outArray[] = $last;
3353
3354 $stringData = $outArray;
3355 }
3356
3357
3358 //----------------------------------------------------------------------
3359 private function getAt($posx, $posy)
3360 {
3361 if (($posx<0)||($posy<0)||($posx>=$this->width)||($posy>=$this->width))
3362 return 0;
3363
3364 return $this->tab[$posy][$posx];
3365 }
3366
3367 //----------------------------------------------------------------------
3368 private function getOnElem($elem, $deltax = 0, $deltay = 0)
3369 {
3370 $posx = $elem[0]+$deltax;
3371 $posy = $elem[1]+$deltay;
3372
3373 if (($posx<0)||($posy<0)||($posx>=$this->width)||($posy>=$this->width))
3374 return 0;
3375
3376 return $this->tab[$posy][$posx];
3377 }
3378
3379 //----------------------------------------------------------------------
3380 private function addGroupElement($groupId, $h, $v, $sx, $sy)
3381 {
3382 $this->groups[$groupId]->total++;
3383 if ($h)
3384 $this->groups[$groupId]->horizontal = true;
3385 if ($v)
3386 $this->groups[$groupId]->vertical = true;
3387 $this->groups[$groupId]->points[] = array($sx, $sy, false);
3388 }
3389
3390 //----------------------------------------------------------------------
3391 public function detectGroups()
3392 {
3393 for ($sy = 0; $sy < $this->width; $sy++) {
3394 for ($sx = 0; $sx < $this->width; $sx++) {
3395
3396 if ($this->tab[$sy][$sx] == 1) { // non-allocated
3397
3398 $gid_left = 0;
3399 $gid_top = 0;
3400
3401 $grouped = false;
3402
3403 if ($sx>0) {
3404
3405 $gid_left = $this->tab[$sy][$sx-1]; // previous on left
3406
3407 if ($gid_left > 1) { // if already in group
3408 $this->tab[$sy][$sx] = $gid_left;
3409 $grouped = true;
3410 $this->addGroupElement($gid_left, true, false, $sx, $sy);
3411 }
3412 }
3413
3414 if ($sy > 0) {
3415
3416 $gid_top = $this->tab[$sy-1][$sx]; // previous on top
3417
3418 if ($gid_top > 1) { //if in group
3419 if (!$grouped) { // and not grouped
3420
3421 $this->tab[$sy][$sx] = $gid_top;
3422 $grouped = true;
3423
3424 $this->addGroupElement($gid_top, false, true, $sx, $sy);
3425
3426 } else if($gid_top != $gid_left) { // was in left group
3427
3428 $grouped = true;
3429
3430 $this->groups[$gid_top]->vertical = true;
3431 $this->groups[$gid_top]->horizontal = true;
3432
3433 $this->groups[$gid_top]->total = $this->groups[$gid_top]->total + $this->groups[$gid_left]->total;
3434
3435 foreach($this->groups[$gid_left]->points as $elem)
3436 $this->tab[$elem[1]][$elem[0]] = $gid_top;
3437
3438 $this->groups[$gid_top]->points = array_values(array_merge($this->groups[$gid_top]->points, $this->groups[$gid_left]->points));
3439 unset($this->groups[$gid_left]);
3440
3441 //refarb group
3442 }
3443 }
3444 }
3445
3446 if (!$grouped) {
3447 $this->curr_group++;
3448 $this->tab[$sy][$sx] = $this->curr_group;
3449 $this->groups[$this->curr_group] = new QRareaGroup($this->curr_group, $sx, $sy);
3450 }
3451
3452 }
3453 }
3454 }
3455 }
3456
3457 //----------------------------------------------------------------------
3458 private function detectSquare($group)
3459 {
3460 $max_x = 0;
3461 $max_y = 0;
3462 $min_x = $this->width;
3463 $min_y = $this->width;
3464
3465 foreach($group->points as $elem) {
3466 $min_x = min($min_x, $elem[QR_AREA_X]);
3467 $max_x = max($max_x, $elem[QR_AREA_X]);
3468 $min_y = min($min_y, $elem[QR_AREA_Y]);
3469 $max_y = max($max_y, $elem[QR_AREA_Y]);
3470 }
3471
3472 return array($min_x, $min_y, $max_x+1, $max_y+1);
3473 }
3474
3475 //----------------------------------------------------------------------
3476 public function detectAreas()
3477 {
3478 $squares = array();
3479 $points = array();
3480 $lshapes = array();
3481
3482 foreach ($this->groups as $groupId=>&$group) {
3483 if ($group->total > 3) {
3484
3485 if ((!$group->vertical)||(!$group->horizontal)) {
3486
3487 $squareCoord = $this->detectSquare($group);
3488 array_unshift($squareCoord, QR_AREA_RECT);
3489
3490 $this->paths[] = $squareCoord;
3491
3492 } else {
3493
3494 $this->detectPaths($group);
3495 unset($group->points);
3496
3497 foreach($group->paths as &$path)
3498 self::rle($path[2]);
3499
3500 $this->paths[] = array(QR_AREA_PATH, $group->paths);
3501 }
3502 } else if (($group->total == 3)&&($group->vertical)&&($group->horizontal)) {
3503 $squareCoord = $this->detectSquare($group);
3504 $variant = 0;
3505
3506 if ($this->getOnElem($squareCoord, 0, 0) != $group->id)
3507 $variant = 0;
3508
3509 if ($this->getOnElem($squareCoord, 1, 0) != $group->id)
3510 $variant = 1;
3511
3512 if ($this->getOnElem($squareCoord, 0, 1) != $group->id)
3513 $variant = 2;
3514
3515 if ($this->getOnElem($squareCoord, 1, 1) != $group->id)
3516 $variant = 3;
3517
3518 $lshapes[] = $squareCoord[QR_AREA_X];
3519 $lshapes[] = $squareCoord[QR_AREA_Y];
3520 $lshapes[] = $variant;
3521
3522 } else if ($group->total >= 2) {
3523 $squareCoord = $this->detectSquare($group);
3524 $squares = array_merge($squares, $squareCoord);
3525 } else if ($group->total == 1) {
3526 $points[] = $group->points[0][0];
3527 $points[] = $group->points[0][1];
3528 }
3529 }
3530
3531 if (count($points) > 0) {
3532 array_unshift($points, QR_AREA_POINT);
3533 $this->paths[] = $points;
3534 }
3535
3536 if (count($squares) > 0) {
3537 array_unshift($squares, QR_AREA_RECT);
3538 $this->paths[] = $squares;
3539 }
3540
3541 if (count($lshapes) > 0) {
3542 array_unshift($lshapes, QR_AREA_LSHAPE);
3543 $this->paths[] = $lshapes;
3544 }
3545 }
3546
3547 //----------------------------------------------------------------------
3548 private function reserveEdgeOnElem($elem, $edgeNo)
3549 {
3550 $this->tab_edges[$elem[QR_AREA_Y]][$elem[QR_AREA_X]][$edgeNo] = true;
3551 }
3552
3553 //----------------------------------------------------------------------
3554 private function reserveEdge($px, $py, $edgeNo)
3555 {
3556 $this->tab_edges[$py][$px][$edgeNo] = true;
3557 }
3558
3559 //----------------------------------------------------------------------
3560 private function markAdjacentEdges($group)
3561 {
3562 foreach($group->points as $elem) {
3563 if ($this->getOnElem($elem, -1, 0) == $group->id)
3564 $this->reserveEdgeOnElem($elem, QR_AREA_W);
3565
3566 if ($this->getOnElem($elem, +1, 0) == $group->id)
3567 $this->reserveEdgeOnElem($elem, QR_AREA_E);
3568
3569 if ($this->getOnElem($elem, 0, -1) == $group->id)
3570 $this->reserveEdgeOnElem($elem, QR_AREA_N);
3571
3572 if ($this->getOnElem($elem, 0, +1) == $group->id)
3573 $this->reserveEdgeOnElem($elem, QR_AREA_S);
3574 }
3575 }
3576
3577 //----------------------------------------------------------------------
3578 private function detectPaths(&$group)
3579 {
3580 $this->markAdjacentEdges($group);
3581
3582 $elem = $group->points[0];
3583 $waylist = $this->findPath($group, $elem[QR_AREA_X], $elem[QR_AREA_Y]);
3584 $group->paths[] = array($elem[QR_AREA_X], $elem[QR_AREA_Y], $waylist);
3585
3586 $tab = array();
3587 foreach($group->points as $elem) {
3588
3589 $edgeTab = $this->tab_edges[$elem[QR_AREA_Y]][$elem[QR_AREA_X]];
3590
3591 if (!( $edgeTab[QR_AREA_N]
3592 && $edgeTab[QR_AREA_E]
3593 && $edgeTab[QR_AREA_S]
3594 && $edgeTab[QR_AREA_W])) {
3595
3596 if (!$edgeTab[QR_AREA_S]) {
3597
3598 $waylistw = $this->findPath($group, $elem[QR_AREA_X], $elem[QR_AREA_Y]+1);
3599 $group->paths[] = array($elem[QR_AREA_X], $elem[QR_AREA_Y]+1, $waylistw);
3600 }
3601 }
3602 }
3603
3604 }
3605
3606 //----------------------------------------------------------------------
3607 private function findPath($group, $sx, $sy)
3608 {
3609 $px = $sx;
3610 $py = $sy;
3611
3612 $waylist = '';
3613 $dir = '';
3614 $lastdir = '';
3615
3616 $moves = array(
3617 // magic :)
3618 0=>'', 1=>'L', 2=>'T', 3=>'L', 4=>'B', 5=>'B', 6=>'B,T', 7=>'B'
3619 ,8=>'R', 9=>'R,L', 10=>'T', 11=>'L',12=>'R',13=>'R',14=>'T',15=>''
3620 );
3621
3622 do
3623 {
3624 $Q = ($this->getAt($px-1, $py-1) == $group->id)?1:0;
3625 $Q += ($this->getAt($px, $py-1) == $group->id)?2:0;
3626 $Q += ($this->getAt($px-1, $py) == $group->id)?4:0;
3627 $Q += ($this->getAt($px, $py) == $group->id)?8:0;
3628
3629 if ($moves[$Q] == '')
3630 throw new Exception('It should NEVER happened!');
3631
3632 $move_expl = explode(',', $moves[$Q]);
3633 $have_way = false;
3634
3635 $dir = '';
3636
3637 while ((count($move_expl) > 0)&&($have_way == false)) {
3638 $way = array_shift($move_expl);
3639
3640 if (($have_way==false)&&($way=='R')&&($this->tab_edges[$py][$px][QR_AREA_N]==false)) {
3641 $have_way = true;
3642 $dir = $way;
3643 $this->reserveEdge($px, $py, QR_AREA_N);
3644 $px++;
3645 }
3646
3647 if (($have_way==false)&&($way=='B')&&($this->tab_edges[$py][$px-1][QR_AREA_E]==false)) {
3648 $have_way = true;
3649 $dir = $way;
3650 $this->reserveEdge($px-1, $py, QR_AREA_E);
3651 $py++;
3652 }
3653
3654 if (($have_way==false)&&($way=='L')&&($this->tab_edges[$py-1][$px-1][QR_AREA_S]==false)) {
3655 $have_way = true;
3656 $dir = $way;
3657 $this->reserveEdge($px-1, $py-1, QR_AREA_S);
3658 $px--;
3659 }
3660
3661 if (($have_way==false)&&($way=='T')&&($this->tab_edges[$py-1][$px][QR_AREA_W]==false)) {
3662 $have_way = true;
3663 $dir = $way;
3664 $this->reserveEdge($px, $py-1, QR_AREA_W);
3665 $py--;
3666 }
3667 }
3668
3669 $waylist .= $dir;
3670
3671 } while (!(($px==$sx)&&($py==$sy)));
3672
3673 return $waylist;
3674 }
3675 }
3676
3677 /** @} */
3678
3679
3680
3681//---- qrcanvas.php -----------------------------
3682
3683
3684
3685
3686/*
3687 * PHP QR Code encoder
3688 *
3689 * CANVAS output
3690 *
3691 * Based on libqrencode C library distributed under LGPL 2.1
3692 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
3693 *
3694 * PHP QR Code is distributed under LGPL 3
3695 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
3696 *
3697 * This library is free software; you can redistribute it and/or
3698 * modify it under the terms of the GNU Lesser General Public
3699 * License as published by the Free Software Foundation; either
3700 * version 3 of the License, or any later version.
3701 *
3702 * This library is distributed in the hope that it will be useful,
3703 * but WITHOUT ANY WARRANTY; without even the implied warranty of
3704 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3705 * Lesser General Public License for more details.
3706 *
3707 * You should have received a copy of the GNU Lesser General Public
3708 * License along with this library; if not, write to the Free Software
3709 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3710 */
3711
3712 /** @addtogroup OutputGroup */
3713 /** @{ */
3714
3715 class QRcanvasOutput extends QRarea {
3716
3717 public function __construct($source_tab)
3718 {
3719 parent::__construct($source_tab);
3720 }
3721
3722 //----------------------------------------------------------------------
3723 public static function encodeNum($num)
3724 {
3725 $addTab = array(0=>'', 1=>'z', 2=>'Z', 3=>'+');
3726 $map = '0123456789abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQRSTUVWXY';
3727 $mapPos = $num % 60;
3728 $mapAdd = (int)($num / 60);
3729
3730 return $addTab[$mapAdd].$map[$mapPos];
3731 }
3732
3733 //----------------------------------------------------------------------
3734 public static function compact_path(&$pathTab)
3735 {
3736 if (count($pathTab) == 0) {
3737 $pathTab = '';
3738 } else {
3739 $pathTab = count($pathTab).','.join(',', $pathTab);
3740 }
3741 }
3742
3743 //----------------------------------------------------------------------
3744 public static function compact_points(&$pointsTab)
3745 {
3746 if (count($pointsTab) == 0) {
3747 $pointsTab = '';
3748 } else {
3749 $compacted = '';
3750 foreach ($pointsTab as $point)
3751 $compacted .= self::encodeNum($point);
3752 $pointsTab = $compacted;
3753 }
3754 }
3755
3756 //----------------------------------------------------------------------
3757 public static function compactCanvasCommands($ops)
3758 {
3759 $accumulated = array();
3760
3761 $accumulated['SR'] = array();
3762 $accumulated['WR'] = array();
3763 $accumulated['SP'] = array();
3764 $accumulated['WP'] = array();
3765 $accumulated['SB'] = array();
3766 $accumulated['WB'] = array();
3767 $accumulated['SO'] = array();
3768
3769 while (count($ops) > 0) {
3770 $color = array_shift($ops);
3771 $opcode = array_shift($ops);
3772
3773 if (($opcode == 'R') || ($opcode == 'P')) {
3774
3775 do {
3776 $num = array_shift($ops);
3777 if (is_int($num)) {
3778 $accumulated[$color.$opcode][] = $num;
3779 } else {
3780 array_unshift($ops, $num);
3781 }
3782
3783 } while ((count($ops) > 0)&&(is_int($num)));
3784
3785
3786 } else if ($opcode == 'B') {
3787
3788 array_shift($ops);
3789
3790 $px = array_shift($ops);
3791 $py = array_shift($ops);
3792
3793 array_shift($ops);
3794
3795 $conftab = array();
3796 $num = array_shift($ops);
3797
3798 while ((count($ops) > 0)&&(!($num === 'E'))) {
3799 $conftab[] = $num;
3800 $num = array_shift($ops);
3801 }
3802
3803 $cc = count($conftab);
3804 $deltas = '';
3805
3806 $lastposx = $px;
3807 $lastposy = $py;
3808
3809 for($pos=0;$pos <$cc; $pos+=2) {
3810
3811 $dx = $lastposx - $conftab[$pos];
3812 $dy = $lastposy - $conftab[$pos+1];
3813
3814 $lastposx = $conftab[$pos];
3815 $lastposy = $conftab[$pos+1];
3816
3817 if ($dx < 0) {
3818 $deltas .= chr(ord('a')-1-$dx);
3819 } else if ($dx > 0) {
3820 $deltas .= chr(ord('A')-1+$dx);
3821 } else {
3822 $deltas .= '0';
3823 }
3824
3825 if ($dy < 0) {
3826 $deltas .= chr(ord('a')-1-$dy);
3827 } else if ($dy > 0) {
3828 $deltas .= chr(ord('A')-1+$dy);
3829 } else {
3830 $deltas .= '0';
3831 }
3832
3833 }
3834
3835 $deltas = strtr($deltas, array(
3836 '00'=>'1',
3837 'aa'=>'2',
3838 'aA'=>'3',
3839 'Aa'=>'4',
3840 'AA'=>'5',
3841 'aB'=>'6',
3842 'Ab'=>'7',
3843 'bA'=>'8',
3844 'Ba'=>'9'
3845 ));
3846
3847 $accumulated[$color.$opcode][] = join(',', array($px, $py, $deltas));
3848 } else if ($opcode == 'O') {
3849 $px = array_shift($ops);
3850 $py = array_shift($ops);
3851
3852 $accumulated[$color.$opcode][] = join(',', array($px, $py));
3853 }
3854 }
3855
3856 self::compact_points($accumulated['SR']);
3857 self::compact_points($accumulated['WR']);
3858 self::compact_points($accumulated['SP']);
3859 self::compact_points($accumulated['WP']);
3860
3861 self::compact_path($accumulated['SB']);
3862 self::compact_path($accumulated['WB']);
3863
3864 if (count($accumulated['SO']) > 0)
3865 $accumulated['SO'] = join(',',$accumulated['SO']);
3866 else $accumulated['SO'] = '';
3867
3868 $mapping = array(
3869 'SO'=>'O',
3870 'SB'=>'B',
3871 'WB'=>'b',
3872 'SR'=>'R',
3873 'WR'=>'r',
3874 'SP'=>'P',
3875 'WP'=>'p'
3876 );
3877
3878 $whole = array();
3879
3880 foreach($mapping as $key=>$symb) {
3881 if ($accumulated[$key]!='')
3882 $whole[] = $symb.','.$accumulated[$key];
3883 }
3884
3885 return join(',', $whole);
3886 }
3887
3888
3889 //----------------------------------------------------------------------
3890 public function getCanvasOps()
3891 {
3892 $ops = array();
3893
3894 foreach ($this->paths as $path) {
3895 switch ($path[0]) {
3896 case QR_AREA_PATH:
3897 $pNum = 0;
3898
3899 foreach($path[1] as $pathDetails) {
3900 if ($pNum == 0) {
3901 $ops[] = 'S';
3902 } else if ($pNum > 0) {
3903 $ops[] = 'W';
3904 }
3905
3906 $ops[] = 'B';
3907
3908 $px = array_shift($pathDetails);
3909 $py = array_shift($pathDetails);
3910
3911 $ops[] = 'M';
3912 $ops[] = $px;
3913 $ops[] = $py;
3914
3915 $rle_steps = array_shift($pathDetails);
3916
3917 $lastOp = '';
3918
3919 while(count($rle_steps) > 0) {
3920
3921 $delta = 1;
3922
3923 $operator = array_shift($rle_steps);
3924 if (($operator != 'R') && ($operator != 'L') && ($operator != 'T') && ($operator != 'B')) {
3925 $delta = (int)$operator;
3926 $operator = array_shift($rle_steps);
3927 }
3928
3929 if ($operator == 'R') $px += $delta;
3930 if ($operator == 'L') $px -= $delta;
3931 if ($operator == 'T') $py -= $delta;
3932 if ($operator == 'B') $py += $delta;
3933
3934 if ($lastOp != 'T')
3935 $ops[] = 'T';
3936
3937 $ops[] = $px;
3938 $ops[] = $py;
3939
3940 $lastOp = 'T';
3941 }
3942
3943 $ops[] = 'E';
3944
3945 $pNum++;
3946 }
3947
3948 break;
3949 case QR_AREA_POINT:
3950
3951 $symb = array_shift($path);
3952
3953 $ops[] = 'S';
3954
3955 $lastOp = '';
3956
3957 while(count($path) > 0) {
3958 $px = array_shift($path);
3959 $py = array_shift($path);
3960
3961 if ($lastOp != 'P')
3962 $ops[] = 'P';
3963
3964 $ops[] = $px;
3965 $ops[] = $py;
3966
3967 $lastOp = 'P';
3968 }
3969
3970 break;
3971
3972 case QR_AREA_RECT:
3973
3974 $symb = array_shift($path);
3975
3976 $ops[] = 'S';
3977
3978 $lastOp = '';
3979
3980 while(count($path) > 0) {
3981 $px = array_shift($path);
3982 $py = array_shift($path);
3983 $ex = array_shift($path);
3984 $ey = array_shift($path);
3985
3986 if ($lastOp != 'R')
3987 $ops[] = 'R';
3988
3989 $ops[] = $px;
3990 $ops[] = $py;
3991 $ops[] = $ex-$px;
3992 $ops[] = $ey-$py;
3993
3994 $lastOp = 'R';
3995 }
3996
3997 break;
3998
3999 case QR_AREA_LSHAPE:
4000
4001 $symb = array_shift($path);
4002
4003 while(count($path) > 0) {
4004 $px = array_shift($path);
4005 $py = array_shift($path);
4006 $mode = (int)array_shift($path);
4007
4008 $pxd = ($mode % 2)?1:0;
4009 $pyd = ($mode > 1)?1:0;
4010
4011 $ops[] = 'S';
4012 $ops[] = 'R';
4013 $ops[] = $px;
4014 $ops[] = $py;
4015 $ops[] = 2;
4016 $ops[] = 2;
4017
4018 $ops[] = 'W';
4019 $ops[] = 'P';
4020 $ops[] = $px+$pxd;
4021 $ops[] = $py+$pyd;
4022 }
4023
4024 break;
4025
4026 case QR_AREA_TRACKER:
4027
4028 $symb = array_shift($path);
4029
4030 $px = array_shift($path);
4031 $py = array_shift($path);
4032
4033 $ops[] = 'S';
4034 $ops[] = 'O';
4035 $ops[] = $px;
4036 $ops[] = $py;
4037
4038 break;
4039 }
4040 }
4041
4042 return self::compactCanvasCommands($ops);
4043 }
4044 }
4045
4046 /** @} */
4047
4048
4049
4050
4051//---- qrsvg.php -----------------------------
4052
4053
4054
4055
4056/*
4057 * PHP QR Code encoder
4058 *
4059 * SVG output support
4060 *
4061 * Based on libqrencode C library distributed under LGPL 2.1
4062 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
4063 *
4064 * PHP QR Code is distributed under LGPL 3
4065 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
4066 *
4067 * This library is free software; you can redistribute it and/or
4068 * modify it under the terms of the GNU Lesser General Public
4069 * License as published by the Free Software Foundation; either
4070 * version 3 of the License, or any later version.
4071 *
4072 * This library is distributed in the hope that it will be useful,
4073 * but WITHOUT ANY WARRANTY; without even the implied warranty of
4074 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4075 * Lesser General Public License for more details.
4076 *
4077 * You should have received a copy of the GNU Lesser General Public
4078 * License along with this library; if not, write to the Free Software
4079 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
4080 */
4081
4082 /** @addtogroup OutputGroup */
4083 /** @{ */
4084
4085 class QRsvgOutput extends QRarea {
4086
4087 public function __construct($source_tab)
4088 {
4089 parent::__construct($source_tab);
4090 }
4091
4092 //----------------------------------------------------------------------
4093 public function mapX($px)
4094 {
4095 return $px;
4096 }
4097
4098 //----------------------------------------------------------------------
4099 public function mapY($py)
4100 {
4101 return $py;
4102 }
4103
4104 //----------------------------------------------------------------------
4105 public function getRawSvg()
4106 {
4107 $lib = array();
4108 $svg = array();
4109
4110 $aggregate_paths = array();
4111
4112 foreach ($this->paths as $path) {
4113 switch ($path[0]) {
4114 case QR_AREA_PATH:
4115 $pNum = 0;
4116
4117 foreach($path[1] as $pathDetails) {
4118
4119 $px = array_shift($pathDetails);
4120 $py = array_shift($pathDetails);
4121 $rle_steps = array_shift($pathDetails);
4122
4123 $aggregate_add = 'M'.$px.','.$py.' ';
4124
4125 while(count($rle_steps) > 0) {
4126
4127 $delta = 1;
4128
4129 $operator = array_shift($rle_steps);
4130 if (($operator != 'R') && ($operator != 'L') && ($operator != 'T') && ($operator != 'B')) {
4131 $delta = (int)$operator;
4132 $operator = array_shift($rle_steps);
4133 }
4134
4135 if ($operator == 'R') $aggregate_add .= 'h'.$delta;
4136 if ($operator == 'L') $aggregate_add .= 'h-'.$delta;
4137 if ($operator == 'T') $aggregate_add .= 'v-'.$delta;
4138 if ($operator == 'B') $aggregate_add .= 'v'.$delta;
4139 }
4140
4141 $aggregate_paths[] = $aggregate_add;
4142
4143 $pNum++;
4144 }
4145
4146 break;
4147 case QR_AREA_POINT:
4148
4149 $symb = array_shift($path);
4150
4151 while(count($path) > 0) {
4152 $px = array_shift($path);
4153 $py = array_shift($path);
4154
4155 $aggregate_paths[] = 'M'.$px.','.$py.' v1h1v-1h-1';
4156 }
4157
4158 break;
4159
4160 case QR_AREA_RECT:
4161
4162 $symb = array_shift($path);
4163
4164 while(count($path) > 0) {
4165 $px = array_shift($path);
4166 $py = array_shift($path);
4167 $ex = array_shift($path);
4168 $ey = array_shift($path);
4169
4170 $w = $ex-$px;
4171 $h = $ey-$py;
4172
4173 $aggregate_paths[] = 'M'.$px.','.$py.' h'.$w.'v'.$h.'h-'.$w.'v-'.$h;
4174 }
4175
4176 break;
4177
4178 case QR_AREA_LSHAPE:
4179
4180 $symb = array_shift($path);
4181
4182 $l_shapes[0] = 'm1,0h1v2h-2v-1h1z';
4183 $l_shapes[1] = 'h1v1h1v1h-2z';
4184 $l_shapes[2] = 'h2v2h-1v-1h-1z';
4185 $l_shapes[3] = 'h2v1h-1v1h-1z';
4186
4187 while(count($path) > 0) {
4188 $px = array_shift($path);
4189 $py = array_shift($path);
4190 $mode = (int)array_shift($path);
4191
4192 $aggregate_paths[] = 'M'.$px.','.$py.' '.$l_shapes[$mode];
4193 }
4194
4195 break;
4196
4197 case QR_AREA_TRACKER:
4198
4199 if (!isset($lib['tracker'])) {
4200 $lib['tracker'] = '<symbol id="tracker"><path d="m 0 7 0 7 7 0 0 -7 -7 0 z m 1 1 5 0 0 5 -5 0 0 -5 z m 1 1 0 3 3 0 0 -3 -3 0 z" style="fill:#000000;stroke:none"></path></symbol>';
4201 }
4202
4203 $symb = array_shift($path);
4204
4205 $px = array_shift($path);
4206 $py = array_shift($path);
4207
4208 $svg[] = '<use x="'.$px.'" y="'.($py-7).'" xlink:href="#tracker"></use>';
4209
4210 break;
4211 }
4212 }
4213
4214 $svg[] = '<path d="'.join(' ', $aggregate_paths).'" style="fill:#000000;stroke:none" ></path>';
4215
4216
4217
4218 return join("\n", $lib)."\n".join("\n", $svg);
4219 }
4220 }
4221
4222 /** @} */
4223
4224
4225
4226
4227//---- qrencode.php -----------------------------
4228
4229
4230
4231
4232/*
4233 * PHP QR Code encoder
4234 *
4235 * Main encoder classes.
4236 *
4237 * Based on libqrencode C library distributed under LGPL 2.1
4238 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
4239 *
4240 * PHP QR Code is distributed under LGPL 3
4241 * Copyright (C) 2010-2013 Dominik Dzienia <deltalab at poczta dot fm>
4242 *
4243 * This library is free software; you can redistribute it and/or
4244 * modify it under the terms of the GNU Lesser General Public
4245 * License as published by the Free Software Foundation; either
4246 * version 3 of the License, or any later version.
4247 *
4248 * This library is distributed in the hope that it will be useful,
4249 * but WITHOUT ANY WARRANTY; without even the implied warranty of
4250 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4251 * Lesser General Public License for more details.
4252 *
4253 * You should have received a copy of the GNU Lesser General Public
4254 * License along with this library; if not, write to the Free Software
4255 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
4256 */
4257
4258 /** @defgroup CoreGroup Standard API Core
4259 Core encoder classes */
4260
4261 /** @addtogroup CoreGroup */
4262 /** @{ */
4263
4264 //##########################################################################
4265 /**
4266 Data block with raw data and it's Error Correction Code data.
4267 */
4268 class QRrsblock {
4269 public $dataLength;
4270 public $data = array();
4271 public $eccLength;
4272 public $ecc = array();
4273
4274 /** Data block Constructor
4275 @param Integer $dl length of data stream
4276 @param Array $data data stream
4277 @param Integer $el ECC length
4278 @param Array $el ECC stream (modified, by reference)
4279 @param QRrsItem $rs RS encoding item
4280 */
4281 public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
4282 {
4283 $rs->encode_rs_char($data, $ecc);
4284
4285 $this->dataLength = $dl;
4286 $this->data = $data;
4287 $this->eccLength = $el;
4288 $this->ecc = $ecc;
4289 }
4290 };
4291
4292 //##########################################################################
4293 /** Raw Code holder.
4294 Contains encoded code data before there are spatialy distributed into frame and masked.
4295 Here goes dividing data into blocks and calculating ECC stream. */
4296 class QRrawcode {
4297
4298 public $version; ///< __Integer__ code Version
4299 public $datacode = array(); ///< __Array__ data stream
4300 public $ecccode = array(); ///< __Array__ ECC Stream
4301 public $blocks; ///< __Integer__ RS Blocks count
4302 public $rsblocks = array(); ///< __Array__ of RSblock, ECC code blocks
4303 public $count; ///< __Integer__ position of currently processed ECC code
4304 public $dataLength; ///< __Integer__ data stream length
4305 public $eccLength; ///< __Integer__ ECC stream length
4306 public $b1; ///< __Integer__ width of code in pixels, used as a modulo base for column overflow
4307
4308 //----------------------------------------------------------------------
4309 /** Raw Code holder Constructor
4310 @param QRinput $input input stream
4311 */
4312 public function __construct(QRinput $input)
4313 {
4314 $spec = array(0,0,0,0,0);
4315
4316 $this->datacode = $input->getByteStream();
4317 if(is_null($this->datacode)) {
4318 throw new Exception('null imput string');
4319 }
4320
4321 QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
4322
4323 $this->version = $input->getVersion();
4324 $this->b1 = QRspec::rsBlockNum1($spec);
4325 $this->dataLength = QRspec::rsDataLength($spec);
4326 $this->eccLength = QRspec::rsEccLength($spec);
4327 $this->ecccode = array_fill(0, $this->eccLength, 0);
4328 $this->blocks = QRspec::rsBlockNum($spec);
4329
4330 $ret = $this->init($spec);
4331 if($ret < 0) {
4332 throw new Exception('block alloc error');
4333 return null;
4334 }
4335
4336 $this->count = 0;
4337 }
4338
4339 //----------------------------------------------------------------------
4340 /** Initializes Raw Code according to current code speciffication
4341 @param Array $spec code speciffigation, as provided by QRspec
4342 */
4343 public function init(array $spec)
4344 {
4345 $dl = QRspec::rsDataCodes1($spec);
4346 $el = QRspec::rsEccCodes1($spec);
4347 $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
4348
4349
4350 $blockNo = 0;
4351 $dataPos = 0;
4352 $eccPos = 0;
4353 for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {
4354 $ecc = array_slice($this->ecccode,$eccPos);
4355 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
4356 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
4357
4358 $dataPos += $dl;
4359 $eccPos += $el;
4360 $blockNo++;
4361 }
4362
4363 if(QRspec::rsBlockNum2($spec) == 0)
4364 return 0;
4365
4366 $dl = QRspec::rsDataCodes2($spec);
4367 $el = QRspec::rsEccCodes2($spec);
4368 $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
4369
4370 if($rs == NULL) return -1;
4371
4372 for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {
4373 $ecc = array_slice($this->ecccode,$eccPos);
4374 $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
4375 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
4376
4377 $dataPos += $dl;
4378 $eccPos += $el;
4379 $blockNo++;
4380 }
4381
4382 return 0;
4383 }
4384
4385 //----------------------------------------------------------------------
4386 /** Gets ECC code
4387 @return Integer ECC byte for current object position
4388 */
4389 public function getCode()
4390 {
4391 $ret = null;
4392
4393 if($this->count < $this->dataLength) {
4394 $row = $this->count % $this->blocks;
4395 $col = $this->count / $this->blocks;
4396 if($col >= $this->rsblocks[0]->dataLength) {
4397 $row += $this->b1;
4398 }
4399 $ret = $this->rsblocks[$row]->data[(int) $col];
4400 } else if($this->count < $this->dataLength + $this->eccLength) {
4401 $row = ($this->count - $this->dataLength) % $this->blocks;
4402 $col = ($this->count - $this->dataLength) / $this->blocks;
4403 $ret = $this->rsblocks[$row]->ecc[(int) $col];
4404 } else {
4405 return 0;
4406 }
4407 $this->count++;
4408
4409 return $ret;
4410 }
4411 }
4412
4413 //##########################################################################
4414 /**
4415 __Main class to create QR-code__.
4416 QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
4417 The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
4418 This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
4419
4420 Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
4421
4422 @abstract Class for generating QR-code images, SVG and HTML5 Canvas
4423 @author Dominik Dzienia
4424 @copyright 2010-2013 Dominik Dzienia and others
4425 @link http://phpqrcode.sourceforge.net
4426 @license http://www.gnu.org/copyleft/lesser.html LGPL
4427 */
4428
4429 class QRcode {
4430
4431 public $version; ///< __Integer__ QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix.
4432 public $width; ///< __Integer__ Width of code table. Because code is square shaped - same as height.
4433 public $data; ///< __Array__ Ready, masked code data.
4434
4435 /** Canvas JS include flag.
4436 If canvas js support library was included, we remember it static in QRcode.
4437 (because file should be included only once)
4438 */
4439 public static $jscanvasincluded = false;
4440
4441 //----------------------------------------------------------------------
4442 /**
4443 Encode mask
4444 Main function responsible for creating code.
4445 We get empty frame, then fill it with data from input, then select best mask and apply it.
4446 If $mask argument is greater than -1 we assume that user want's that specific mask number (ranging form 0-7) to be used.
4447 Otherwise (when $mask is -1) mask is detected using algorithm depending of global configuration,
4448
4449 @param QRinput $input data object
4450 @param Integer $mask sugested masking mode
4451 @return QRcode $this (current instance)
4452 */
4453 public function encodeMask(QRinput $input, $mask)
4454 {
4455 if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
4456 throw new Exception('wrong version');
4457 }
4458 if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
4459 throw new Exception('wrong level');
4460 }
4461
4462 $raw = new QRrawcode($input);
4463
4464 QRtools::markTime('after_raw');
4465
4466 $version = $raw->version;
4467 $width = QRspec::getWidth($version);
4468 $frame = QRspec::newFrame($version);
4469
4470 $filler = new QRframeFiller($width, $frame);
4471 if(is_null($filler)) {
4472 return NULL;
4473 }
4474
4475 // inteleaved data and ecc codes
4476 for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
4477 $code = $raw->getCode();
4478 $bit = 0x80;
4479 for($j=0; $j<8; $j++) {
4480 $addr = $filler->next();
4481 $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
4482 $bit = $bit >> 1;
4483 }
4484 }
4485
4486 QRtools::markTime('after_filler');
4487
4488 unset($raw);
4489
4490 // remainder bits
4491 $j = QRspec::getRemainder($version);
4492 for($i=0; $i<$j; $i++) {
4493 $addr = $filler->next();
4494 $filler->setFrameAt($addr, 0x02);
4495 }
4496
4497 $frame = $filler->frame;
4498 unset($filler);
4499
4500
4501 // masking
4502 $maskObj = new QRmask();
4503 if($mask < 0) {
4504
4505 if (QR_FIND_BEST_MASK) {
4506 $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
4507 } else {
4508 $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
4509 }
4510 } else {
4511 $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
4512 }
4513
4514 if($masked == NULL) {
4515 return NULL;
4516 }
4517
4518 QRtools::markTime('after_mask');
4519
4520 $this->version = $version;
4521 $this->width = $width;
4522 $this->data = $masked;
4523
4524 return $this;
4525 }
4526
4527 //----------------------------------------------------------------------
4528 /**
4529 Encode input with mask detection.
4530 Shorthand for encodeMask, without specifing particular, static mask number.
4531
4532 @param QRinput $input data object to be encoded
4533 @return
4534 */
4535 public function encodeInput(QRinput $input)
4536 {
4537 return $this->encodeMask($input, -1);
4538 }
4539
4540 //----------------------------------------------------------------------
4541 /**
4542 Encode string, forcing 8-bit encoding
4543 @param String $string input string
4544 @param Integer $version code version (size of code area)
4545 @param Integer $level ECC level (see: Global Constants -> Levels of Error Correction)
4546 @return QRcode $this (current instance)
4547 */
4548 public function encodeString8bit($string, $version, $level)
4549 {
4550 if($string == NULL) {
4551 throw new Exception('empty string!');
4552 return NULL;
4553 }
4554
4555 $input = new QRinput($version, $level);
4556 if($input == NULL) return NULL;
4557
4558 $ret = $input->append(QR_MODE_8, strlen($string), str_split($string));
4559 if($ret < 0) {
4560 unset($input);
4561 return NULL;
4562 }
4563 return $this->encodeInput($input);
4564 }
4565
4566 //----------------------------------------------------------------------
4567 /**
4568 Encode string, using optimal encodings.
4569 Encode string dynamically adjusting encoding for subsections of string to
4570 minimize resulting code size. For complex string it will split string into
4571 subsections: Numerical, Alphanumerical or 8-bit.
4572 @param String $string input string
4573 @param Integer $version code version (size of code area)
4574 @param String $level ECC level (see: Global Constants -> Levels of Error Correction)
4575 @param Integer $hint __QR_MODE_8__ or __QR_MODE_KANJI__, Because Kanji encoding
4576 is kind of 8 bit encoding we need to hint encoder to use Kanji mode explicite.
4577 (otherwise it may try to encode it as plain 8 bit stream)
4578 @param Boolean $casesensitive hint if given string is case-sensitive, because
4579 if not - encoder may use optimal QR_MODE_AN instead of QR_MODE_8
4580 @return QRcode $this (current instance)
4581 */
4582 public function encodeString($string, $version, $level, $hint, $casesensitive)
4583 {
4584
4585 if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
4586 throw new Exception('bad hint');
4587 return NULL;
4588 }
4589
4590 $input = new QRinput($version, $level);
4591 if($input == NULL) return NULL;
4592
4593 $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
4594 if($ret < 0) {
4595 return NULL;
4596 }
4597
4598 return $this->encodeInput($input);
4599 }
4600
4601 //######################################################################
4602 /**
4603 Creates PNG image containing QR-Code.
4604 Simple helper function to create QR-Code Png image with one static call.
4605 @param String $text text string to encode
4606 @param String $outfile (optional) output file name, if __false__ outputs to browser with required headers
4607 @param Integer $level (optional) error correction level __QR_ECLEVEL_L__, __QR_ECLEVEL_M__, __QR_ECLEVEL_Q__ or __QR_ECLEVEL_H__
4608 @param Integer $size (optional) pixel size, multiplier for each 'virtual' pixel
4609 @param Integer $margin (optional) code margin (silent zone) in 'virtual' pixels
4610 @param Boolean $saveandprint (optional) if __true__ code is outputed to browser and saved to file, otherwise only saved to file. It is effective only if $outfile is specified.
4611 */
4612
4613 public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false)
4614 {
4615 $enc = QRencode::factory($level, $size, $margin);
4616 return $enc->encodePNG($text, $outfile, $saveandprint=false);
4617 }
4618
4619 //----------------------------------------------------------------------
4620 /**
4621 Creates text (1's & 0's) containing QR-Code.
4622 Simple helper function to create QR-Code text with one static call.
4623 @param String $text text string to encode
4624 @param String $outfile (optional) output file name, when __false__ file is not saved
4625 @param Integer $level (optional) error correction level __QR_ECLEVEL_L__, __QR_ECLEVEL_M__, __QR_ECLEVEL_Q__ or __QR_ECLEVEL_H__
4626 @param Integer $size (optional) pixel size, multiplier for each 'virtual' pixel
4627 @param Integer $margin (optional) code margin (silent zone) in 'virtual' pixels
4628 @return Array containing line of code with 1 and 0 for every code line
4629 */
4630
4631 public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
4632 {
4633 $enc = QRencode::factory($level, $size, $margin);
4634 return $enc->encode($text, $outfile);
4635 }
4636
4637 //----------------------------------------------------------------------
4638 /**
4639 Creates Raw Array containing QR-Code.
4640 Simple helper function to create QR-Code array with one static call.
4641 @param String $text text string to encode
4642 @param Boolean $outfile (optional) not used, shuold be __false__
4643 @param Integer $level (optional) error correction level __QR_ECLEVEL_L__, __QR_ECLEVEL_M__, __QR_ECLEVEL_Q__ or __QR_ECLEVEL_H__
4644 @param Integer $size (optional) pixel size, multiplier for each 'virtual' pixel
4645 @param Integer $margin (optional) code margin (silent zone) in 'virtual' pixels
4646 @return Array containing Raw QR code
4647 */
4648
4649 public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
4650 {
4651 $enc = QRencode::factory($level, $size, $margin);
4652 return $enc->encodeRAW($text, $outfile);
4653 }
4654
4655 //----------------------------------------------------------------------
4656 /**
4657 Creates Html+JS code to draw QR-Code with HTML5 Canvas.
4658 Simple helper function to create QR-Code array with one static call.
4659 @param String $text text string to encode
4660 @param String $elemId (optional) target Canvas tag id attribute, if __false__ Canvas tag with auto id will be created
4661 @param Integer $level (optional) error correction level __QR_ECLEVEL_L__, __QR_ECLEVEL_M__, __QR_ECLEVEL_Q__ or __QR_ECLEVEL_H__
4662 @param Integer $width (optional) CANVAS element width (sam as height)
4663 @param Integer $size (optional) pixel size, multiplier for each 'virtual' pixel
4664 @param Integer $margin (optional) code margin (silent zone) in 'virtual' pixels
4665 @param Boolean $autoInclude (optional) if __true__, required qrcanvas.js lib will be included (only once)
4666 @return String containing JavaScript creating the code, Canvas element (when $elemId is __false__) and script tag with required lib (when $autoInclude is __true__ and not yet included)
4667 */
4668
4669 public static function canvas($text, $elemId = false, $level = QR_ECLEVEL_L, $width = false, $size = false, $margin = 4, $autoInclude = false)
4670 {
4671 $html = '';
4672 $extra = '';
4673
4674 if ($autoInclude) {
4675 if (!self::$jscanvasincluded) {
4676 self::$jscanvasincluded = true;
4677 echo '<script type="text/javascript" src="qrcanvas.js"></script>';
4678 }
4679 }
4680
4681 $enc = QRencode::factory($level, 1, 0);
4682 $tab_src = $enc->encode($text, false);
4683 $area = new QRcanvasOutput($tab_src);
4684 $area->detectGroups();
4685 $area->detectAreas();
4686
4687 if ($elemId === false) {
4688 $elemId = 'qrcode-'.md5(mt_rand(1000,1000000).'.'.mt_rand(1000,1000000).'.'.mt_rand(1000,1000000).'.'.mt_rand(1000,1000000));
4689
4690 if ($width == false) {
4691 if (($size !== false) && ($size > 0)) {
4692 $width = ($area->getWidth()+(2*$margin)) * $size;
4693 } else {
4694 $width = ($area->getWidth()+(2*$margin)) * 4;
4695 }
4696 }
4697
4698 $html .= '<canvas id="'.$elemId.'" width="'.$width.'" height="'.$width.'">Your browser does not support CANVAS tag! Please upgrade to modern version of FireFox, Opera, Chrome or Safari/Webkit based browser</canvas>';
4699 }
4700
4701 if ($width !== false) {
4702 $extra .= ', '.$width.', '.$width;
4703 }
4704
4705 if ($margin !== false) {
4706 $extra .= ', '.$margin.', '.$margin;
4707 }
4708
4709 $html .= '<script>if(eval("typeof "+\'QRdrawCode\'+"==\'function\'")){QRdrawCode(QRdecompactOps(\''.$area->getCanvasOps().'\')'."\n".', \''.$elemId.'\', '.$area->getWidth().' '.$extra.');}else{alert(\'Please include qrcanvas.js!\');}</script>';
4710
4711 return $html;
4712 }
4713
4714 //----------------------------------------------------------------------
4715 /**
4716 Creates SVG with QR-Code.
4717 Simple helper function to create QR-Code SVG with one static call.
4718 @param String $text text string to encode
4719 @param Boolean $elemId (optional) target SVG tag id attribute, if __false__ SVG tag with auto id will be created
4720 @param String $outfile (optional) output file name, when __false__ file is not saved
4721 @param Integer $level (optional) error correction level __QR_ECLEVEL_L__, __QR_ECLEVEL_M__, __QR_ECLEVEL_Q__ or __QR_ECLEVEL_H__
4722 @param Integer $width (optional) SVG element width (sam as height)
4723 @param Integer $size (optional) pixel size, multiplier for each 'virtual' pixel
4724 @param Integer $margin (optional) code margin (silent zone) in 'virtual' pixels
4725 @param Boolean $compress (optional) if __true__, compressed SVGZ (instead plaintext SVG) is saved to file
4726 @return String containing SVG tag
4727 */
4728
4729 public static function svg($text, $elemId = false, $outFile = false, $level = QR_ECLEVEL_L, $width = false, $size = false, $margin = 4, $compress = false)
4730 {
4731 $enc = QRencode::factory($level, 1, 0);
4732 $tab_src = $enc->encode($text, false);
4733 $area = new QRsvgOutput($tab_src);
4734 $area->detectGroups();
4735 $area->detectAreas();
4736
4737 if ($elemId === false) {
4738 $elemId = 'qrcode-'.md5(mt_rand(1000,1000000).'.'.mt_rand(1000,1000000).'.'.mt_rand(1000,1000000).'.'.mt_rand(1000,1000000));
4739
4740 if ($width == false) {
4741 if (($size !== false) && ($size > 0)) {
4742 $width = ($area->getWidth()+(2*$margin)) * $size;
4743 } else {
4744 $width = ($area->getWidth()+(2*$margin)) * 4;
4745 }
4746 }
4747 }
4748
4749 $svg = '<svg xmlns="http://www.w3.org/2000/svg"
4750 xmlns:xlink="http://www.w3.org/1999/xlink"
4751 version="1.1"
4752 baseProfile="full"
4753 viewBox="'.(-$margin).' '.(-$margin).' '.($area->getWidth()+($margin*2)).' '.($area->getWidth()+($margin*2)).'"
4754 width="'.$width.'"
4755 height="'.$width.'"
4756 id="'.$elemId.'">'."\n";
4757
4758 $svg .= $area->getRawSvg().'</svg>';
4759
4760 if ($outFile !== false) {
4761 $xmlPreamble = '<?xml version="1.0" encoding="UTF-8" standalone="no"'."\n";
4762 $svgContent = $xmlPreamble.$svg;
4763
4764 if ($compress === true) {
4765 file_put_contents($outFile, gzencode($svgContent));
4766 } else {
4767 file_put_contents($outFile, $svgContent);
4768 }
4769 }
4770
4771 return $svg;
4772 }
4773 }
4774
4775 //##########################################################################
4776 /** Fills frame with data.
4777 Each empty frame consist of markers, timing symbols and format configuration.
4778 Remaining place is place for data, and should be filled according to QR Code spec.
4779 */
4780 class QRframeFiller {
4781
4782 public $width; ///< __Integer__ Frame width
4783 public $frame; ///< __Array__ Frame itself
4784 public $x; ///< __Integer__ current X position
4785 public $y; ///< __Integer__ current Y position
4786 public $dir; ///< __Integer__ direction
4787 public $bit; ///< __Integer__ bit
4788
4789 //----------------------------------------------------------------------
4790 /** Frame filler Constructor.
4791 @param Integer $width frame size
4792 @param Array $frame Frame array
4793 */
4794 public function __construct($width, &$frame)
4795 {
4796 $this->width = $width;
4797 $this->frame = $frame;
4798 $this->x = $width - 1;
4799 $this->y = $width - 1;
4800 $this->dir = -1;
4801 $this->bit = -1;
4802 }
4803
4804 //----------------------------------------------------------------------
4805 /** Sets frame code at given position.
4806 @param Array $at position, map containing __x__ and __y__ coordinates
4807 @param Integer $val value to set
4808 */
4809 public function setFrameAt($at, $val)
4810 {
4811 $this->frame[$at['y']][$at['x']] = chr($val);
4812 }
4813
4814 //----------------------------------------------------------------------
4815 /** Gets frame code from given position.
4816 @param Array $at position, map containing __x__ and __y__ coordinates
4817 @return Integer value at requested position
4818 */
4819 public function getFrameAt($at)
4820 {
4821 return ord($this->frame[$at['y']][$at['x']]);
4822 }
4823
4824 //----------------------------------------------------------------------
4825 /** Proceed to next code point. */
4826 public function next()
4827 {
4828 do {
4829
4830 if($this->bit == -1) {
4831 $this->bit = 0;
4832 return array('x'=>$this->x, 'y'=>$this->y);
4833 }
4834
4835 $x = $this->x;
4836 $y = $this->y;
4837 $w = $this->width;
4838
4839 if($this->bit == 0) {
4840 $x--;
4841 $this->bit++;
4842 } else {
4843 $x++;
4844 $y += $this->dir;
4845 $this->bit--;
4846 }
4847
4848 if($this->dir < 0) {
4849 if($y < 0) {
4850 $y = 0;
4851 $x -= 2;
4852 $this->dir = 1;
4853 if($x == 6) {
4854 $x--;
4855 $y = 9;
4856 }
4857 }
4858 } else {
4859 if($y == $w) {
4860 $y = $w - 1;
4861 $x -= 2;
4862 $this->dir = -1;
4863 if($x == 6) {
4864 $x--;
4865 $y -= 8;
4866 }
4867 }
4868 }
4869 if($x < 0 || $y < 0) return null;
4870
4871 $this->x = $x;
4872 $this->y = $y;
4873
4874 } while(ord($this->frame[$y][$x]) & 0x80);
4875
4876 return array('x'=>$x, 'y'=>$y);
4877 }
4878
4879 } ;
4880
4881 //##########################################################################
4882 /** QR Code encoder.
4883 Encoder is used by QRCode to create simple static code generators. */
4884 class QRencode {
4885
4886 public $casesensitive = true; ///< __Boolean__ does input stream id case sensitive, if not encoder may use more optimal charsets
4887 public $eightbit = false; ///< __Boolean__ does input stream is 8 bit
4888
4889 public $version = 0; ///< __Integer__ code version (total size) if __0__ - will be auto-detected
4890 public $size = 3; ///< __Integer__ pixel zoom factor, multiplier to map virtual code pixels to image output pixels
4891 public $margin = 4; ///< __Integer__ margin (silent zone) size, in code pixels
4892
4893 public $structured = 0; ///< Structured QR codes. Not supported.
4894
4895 public $level = QR_ECLEVEL_L; ///< __Integer__ error correction level __QR_ECLEVEL_L__, __QR_ECLEVEL_M__, __QR_ECLEVEL_Q__ or __QR_ECLEVEL_H__
4896 public $hint = QR_MODE_8; ///< __Integer__ encoding hint, __QR_MODE_8__ or __QR_MODE_KANJI__, Because Kanji encoding is kind of 8 bit encoding we need to hint encoder to use Kanji mode explicite. (otherwise it may try to encode it as plain 8 bit stream)
4897
4898 //----------------------------------------------------------------------
4899 /** Encoder instances factory.
4900 @param Integer $level error correction level __QR_ECLEVEL_L__, __QR_ECLEVEL_M__, __QR_ECLEVEL_Q__ or __QR_ECLEVEL_H__
4901 @param Integer $size pixel zoom factor, multiplier to map virtual code pixels to image output pixels
4902 @param Integer $margin margin (silent zone) size, in code pixels
4903 @return builded QRencode instance
4904 */
4905 public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)
4906 {
4907 $enc = new QRencode();
4908 $enc->size = $size;
4909 $enc->margin = $margin;
4910
4911 switch ($level.'') {
4912 case '0':
4913 case '1':
4914 case '2':
4915 case '3':
4916 $enc->level = $level;
4917 break;
4918 case 'l':
4919 case 'L':
4920 $enc->level = QR_ECLEVEL_L;
4921 break;
4922 case 'm':
4923 case 'M':
4924 $enc->level = QR_ECLEVEL_M;
4925 break;
4926 case 'q':
4927 case 'Q':
4928 $enc->level = QR_ECLEVEL_Q;
4929 break;
4930 case 'h':
4931 case 'H':
4932 $enc->level = QR_ECLEVEL_H;
4933 break;
4934 }
4935
4936 return $enc;
4937 }
4938
4939 //----------------------------------------------------------------------
4940 /** Encodes input into Raw code table.
4941 @param String $intext input text
4942 @param Boolean $notused (optional, not used) placeholder for similar outfile parameter
4943 @return __Array__ Raw code frame
4944 */
4945 public function encodeRAW($intext, $notused = false)
4946 {
4947 $code = new QRcode();
4948
4949 if($this->eightbit) {
4950 $code->encodeString8bit($intext, $this->version, $this->level);
4951 } else {
4952 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
4953 }
4954
4955 return $code->data;
4956 }
4957
4958 //----------------------------------------------------------------------
4959 /** Encodes input into binary code table.
4960 @param String $intext input text
4961 @param String $outfile (optional) output file to save code table, if __false__ file will be not saved
4962 @return __Array__ binary code frame
4963 */
4964 public function encode($intext, $outfile = false)
4965 {
4966 $code = new QRcode();
4967
4968 if($this->eightbit) {
4969 $code->encodeString8bit($intext, $this->version, $this->level);
4970 } else {
4971 $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
4972 }
4973
4974 QRtools::markTime('after_encode');
4975
4976 $binarized = QRtools::binarize($code->data);
4977 if ($outfile!== false) {
4978 file_put_contents($outfile, join("\n", $binarized));
4979 }
4980
4981 return $binarized;
4982 }
4983
4984 //----------------------------------------------------------------------
4985 /** Encodes input into PNG image.
4986 @param String $intext input text
4987 @param String $outfile (optional) output file name, if __false__ outputs to browser with required headers
4988 @param Boolean $saveandprint (optional) if __true__ code is outputed to browser and saved to file, otherwise only saved to file. It is effective only if $outfile is specified.
4989 */
4990 public function encodePNG($intext, $outfile = false, $saveandprint=false)
4991 {
4992 try {
4993
4994 ob_start();
4995 $tab = $this->encode($intext);
4996 $err = ob_get_contents();
4997 ob_end_clean();
4998
4999 if ($err != '')
5000 QRtools::log($outfile, $err);
5001
5002 $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
5003
5004 QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
5005
5006 } catch (Exception $e) {
5007
5008 QRtools::log($outfile, $e->getMessage());
5009
5010 }
5011 }
5012 }
5013
5014 /** @}*/
5015