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