]>
git.wh0rd.org - tt-rss.git/blob - lib/phpqrcode/qrinput.php
7 * Based on libqrencode C library distributed under LGPL 2.1
8 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
10 * PHP QR Code is distributed under LGPL 3
11 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 3 of the License, or any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 define('STRUCTURE_HEADER_BITS', 20);
29 define('MAX_STRUCTURED_SYMBOLS', 16);
38 public function __construct($mode, $size, $data, $bstream = null)
40 $setData = array_slice($data, 0, $size);
42 if (count($setData) < $size) {
43 $setData = array_merge($setData, array_fill(0,$size-count($setData),0));
46 if(!QRinput
::check($mode, $size, $setData)) {
47 throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
53 $this->data
= $setData;
54 $this->bstream
= $bstream;
57 //----------------------------------------------------------------------
58 public function encodeModeNum($version)
62 $words = (int)($this->size
/ 3);
63 $bs = new QRbitstream();
66 $bs->appendNum(4, $val);
67 $bs->appendNum(QRspec
::lengthIndicator(QR_MODE_NUM
, $version), $this->size
);
69 for($i=0; $i<$words; $i++
) {
70 $val = (ord($this->data
[$i*3 ]) - ord('0')) * 100;
71 $val +
= (ord($this->data
[$i*3+
1]) - ord('0')) * 10;
72 $val +
= (ord($this->data
[$i*3+
2]) - ord('0'));
73 $bs->appendNum(10, $val);
76 if($this->size
- $words * 3 == 1) {
77 $val = ord($this->data
[$words*3]) - ord('0');
78 $bs->appendNum(4, $val);
79 } else if($this->size
- $words * 3 == 2) {
80 $val = (ord($this->data
[$words*3 ]) - ord('0')) * 10;
81 $val +
= (ord($this->data
[$words*3+
1]) - ord('0'));
82 $bs->appendNum(7, $val);
88 } catch (Exception
$e) {
93 //----------------------------------------------------------------------
94 public function encodeModeAn($version)
97 $words = (int)($this->size
/ 2);
98 $bs = new QRbitstream();
100 $bs->appendNum(4, 0x02);
101 $bs->appendNum(QRspec
::lengthIndicator(QR_MODE_AN
, $version), $this->size
);
103 for($i=0; $i<$words; $i++
) {
104 $val = (int)QRinput
::lookAnTable(ord($this->data
[$i*2 ])) * 45;
105 $val +
= (int)QRinput
::lookAnTable(ord($this->data
[$i*2+
1]));
107 $bs->appendNum(11, $val);
110 if($this->size
& 1) {
111 $val = QRinput
::lookAnTable(ord($this->data
[$words * 2]));
112 $bs->appendNum(6, $val);
115 $this->bstream
= $bs;
118 } catch (Exception
$e) {
123 //----------------------------------------------------------------------
124 public function encodeMode8($version)
127 $bs = new QRbitstream();
129 $bs->appendNum(4, 0x4);
130 $bs->appendNum(QRspec
::lengthIndicator(QR_MODE_8
, $version), $this->size
);
132 for($i=0; $i<$this->size
; $i++
) {
133 $bs->appendNum(8, ord($this->data
[$i]));
136 $this->bstream
= $bs;
139 } catch (Exception
$e) {
144 //----------------------------------------------------------------------
145 public function encodeModeKanji($version)
149 $bs = new QRbitrtream();
151 $bs->appendNum(4, 0x8);
152 $bs->appendNum(QRspec
::lengthIndicator(QR_MODE_KANJI
, $version), (int)($this->size
/ 2));
154 for($i=0; $i<$this->size
; $i+
=2) {
155 $val = (ord($this->data
[$i]) << 8) |
ord($this->data
[$i+
1]);
162 $h = ($val >> 8) * 0xc0;
163 $val = ($val & 0xff) +
$h;
165 $bs->appendNum(13, $val);
168 $this->bstream
= $bs;
171 } catch (Exception
$e) {
176 //----------------------------------------------------------------------
177 public function encodeModeStructure()
180 $bs = new QRbitstream();
182 $bs->appendNum(4, 0x03);
183 $bs->appendNum(4, ord($this->data
[1]) - 1);
184 $bs->appendNum(4, ord($this->data
[0]) - 1);
185 $bs->appendNum(8, ord($this->data
[2]));
187 $this->bstream
= $bs;
190 } catch (Exception
$e) {
195 //----------------------------------------------------------------------
196 public function estimateBitStreamSizeOfEntry($version)
203 switch($this->mode
) {
204 case QR_MODE_NUM
: $bits = QRinput
::estimateBitsModeNum($this->size
); break;
205 case QR_MODE_AN
: $bits = QRinput
::estimateBitsModeAn($this->size
); break;
206 case QR_MODE_8
: $bits = QRinput
::estimateBitsMode8($this->size
); break;
207 case QR_MODE_KANJI
: $bits = QRinput
::estimateBitsModeKanji($this->size
);break;
208 case QR_MODE_STRUCTURE
: return STRUCTURE_HEADER_BITS
;
213 $l = QRspec
::lengthIndicator($this->mode
, $version);
215 $num = (int)(($this->size +
$m - 1) / $m);
217 $bits +
= $num * (4 +
$l);
222 //----------------------------------------------------------------------
223 public function encodeBitStream($version)
227 unset($this->bstream
);
228 $words = QRspec
::maximumWords($this->mode
, $version);
230 if($this->size
> $words) {
232 $st1 = new QRinputItem($this->mode
, $words, $this->data
);
233 $st2 = new QRinputItem($this->mode
, $this->size
- $words, array_slice($this->data
, $words));
235 $st1->encodeBitStream($version);
236 $st2->encodeBitStream($version);
238 $this->bstream
= new QRbitstream();
239 $this->bstream
->append($st1->bstream
);
240 $this->bstream
->append($st2->bstream
);
249 switch($this->mode
) {
250 case QR_MODE_NUM
: $ret = $this->encodeModeNum($version); break;
251 case QR_MODE_AN
: $ret = $this->encodeModeAn($version); break;
252 case QR_MODE_8
: $ret = $this->encodeMode8($version); break;
253 case QR_MODE_KANJI
: $ret = $this->encodeModeKanji($version);break;
254 case QR_MODE_STRUCTURE
: $ret = $this->encodeModeStructure(); break;
264 return $this->bstream
->size();
266 } catch (Exception
$e) {
272 //##########################################################################
281 //----------------------------------------------------------------------
282 public function __construct($version = 0, $level = QR_ECLEVEL_L
)
284 if ($version < 0 ||
$version > QRSPEC_VERSION_MAX ||
$level > QR_ECLEVEL_H
) {
285 throw new Exception('Invalid version no');
289 $this->version
= $version;
290 $this->level
= $level;
293 //----------------------------------------------------------------------
294 public function getVersion()
296 return $this->version
;
299 //----------------------------------------------------------------------
300 public function setVersion($version)
302 if($version < 0 ||
$version > QRSPEC_VERSION_MAX
) {
303 throw new Exception('Invalid version no');
307 $this->version
= $version;
312 //----------------------------------------------------------------------
313 public function getErrorCorrectionLevel()
318 //----------------------------------------------------------------------
319 public function setErrorCorrectionLevel($level)
321 if($level > QR_ECLEVEL_H
) {
322 throw new Exception('Invalid ECLEVEL');
326 $this->level
= $level;
331 //----------------------------------------------------------------------
332 public function appendEntry(QRinputItem
$entry)
334 $this->items
[] = $entry;
337 //----------------------------------------------------------------------
338 public function append($mode, $size, $data)
341 $entry = new QRinputItem($mode, $size, $data);
342 $this->items
[] = $entry;
344 } catch (Exception
$e) {
349 //----------------------------------------------------------------------
351 public function insertStructuredAppendHeader($size, $index, $parity)
353 if( $size > MAX_STRUCTURED_SYMBOLS
) {
354 throw new Exception('insertStructuredAppendHeader wrong size');
357 if( $index <= 0 ||
$index > MAX_STRUCTURED_SYMBOLS
) {
358 throw new Exception('insertStructuredAppendHeader wrong index');
361 $buf = array($size, $index, $parity);
364 $entry = new QRinputItem(QR_MODE_STRUCTURE
, 3, buf
);
365 array_unshift($this->items
, $entry);
367 } catch (Exception
$e) {
372 //----------------------------------------------------------------------
373 public function calcParity()
377 foreach($this->items
as $item) {
378 if($item->mode
!= QR_MODE_STRUCTURE
) {
379 for($i=$item->size
-1; $i>=0; $i--) {
380 $parity ^
= $item->data
[$i];
388 //----------------------------------------------------------------------
389 public static function checkModeNum($size, $data)
391 for($i=0; $i<$size; $i++
) {
392 if((ord($data[$i]) < ord('0')) ||
(ord($data[$i]) > ord('9'))){
400 //----------------------------------------------------------------------
401 public static function estimateBitsModeNum($size)
406 switch($size - $w * 3) {
420 //----------------------------------------------------------------------
421 public static $anTable = array(
422 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
423 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
424 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
425 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1,
426 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
427 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
428 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
429 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
432 //----------------------------------------------------------------------
433 public static function lookAnTable($c)
435 return (($c > 127)?
-1:self
::$anTable[$c]);
438 //----------------------------------------------------------------------
439 public static function checkModeAn($size, $data)
441 for($i=0; $i<$size; $i++
) {
442 if (self
::lookAnTable(ord($data[$i])) == -1) {
450 //----------------------------------------------------------------------
451 public static function estimateBitsModeAn($size)
453 $w = (int)($size / 2);
463 //----------------------------------------------------------------------
464 public static function estimateBitsMode8($size)
469 //----------------------------------------------------------------------
470 public function estimateBitsModeKanji($size)
472 return (int)(($size / 2) * 13);
475 //----------------------------------------------------------------------
476 public static function checkModeKanji($size, $data)
481 for($i=0; $i<$size; $i+
=2) {
482 $val = (ord($data[$i]) << 8) |
ord($data[$i+
1]);
484 ||
($val > 0x9ffc && $val < 0xe040)
493 /***********************************************************************
495 **********************************************************************/
497 public static function check($mode, $size, $data)
503 case QR_MODE_NUM
: return self
::checkModeNum($size, $data); break;
504 case QR_MODE_AN
: return self
::checkModeAn($size, $data); break;
505 case QR_MODE_KANJI
: return self
::checkModeKanji($size, $data); break;
506 case QR_MODE_8
: return true; break;
507 case QR_MODE_STRUCTURE
: return true; break;
517 //----------------------------------------------------------------------
518 public function estimateBitStreamSize($version)
522 foreach($this->items
as $item) {
523 $bits +
= $item->estimateBitStreamSizeOfEntry($version);
529 //----------------------------------------------------------------------
530 public function estimateVersion()
536 $bits = $this->estimateBitStreamSize($prev);
537 $version = QRspec
::getMinimumVersion((int)(($bits +
7) / 8), $this->level
);
541 } while ($version > $prev);
546 //----------------------------------------------------------------------
547 public static function lengthOfCode($mode, $version, $bits)
549 $payload = $bits - 4 - QRspec
::lengthIndicator($mode, $version);
552 $chunks = (int)($payload / 10);
553 $remain = $payload - $chunks * 10;
557 } else if($remain >= 4) {
562 $chunks = (int)($payload / 11);
563 $remain = $payload - $chunks * 11;
569 $size = (int)($payload / 8);
572 $size = (int)(($payload / 13) * 2);
574 case QR_MODE_STRUCTURE
:
575 $size = (int)($payload / 8);
582 $maxsize = QRspec
::maximumWords($mode, $version);
583 if($size < 0) $size = 0;
584 if($size > $maxsize) $size = $maxsize;
589 //----------------------------------------------------------------------
590 public function createBitStream()
594 foreach($this->items
as $item) {
595 $bits = $item->encodeBitStream($this->version
);
606 //----------------------------------------------------------------------
607 public function convertData()
609 $ver = $this->estimateVersion();
610 if($ver > $this->getVersion()) {
611 $this->setVersion($ver);
615 $bits = $this->createBitStream();
620 $ver = QRspec
::getMinimumVersion((int)(($bits +
7) / 8), $this->level
);
622 throw new Exception('WRONG VERSION');
624 } else if($ver > $this->getVersion()) {
625 $this->setVersion($ver);
634 //----------------------------------------------------------------------
635 public function appendPaddingBit(&$bstream)
637 $bits = $bstream->size();
638 $maxwords = QRspec
::getDataLength($this->version
, $this->level
);
639 $maxbits = $maxwords * 8;
641 if ($maxbits == $bits) {
645 if ($maxbits - $bits < 5) {
646 return $bstream->appendNum($maxbits - $bits, 0);
650 $words = (int)(($bits +
7) / 8);
652 $padding = new QRbitstream();
653 $ret = $padding->appendNum($words * 8 - $bits +
4, 0);
658 $padlen = $maxwords - $words;
663 for($i=0; $i<$padlen; $i++
) {
664 $padbuf[$i] = ($i&1)?
0x11:0xec;
667 $ret = $padding->appendBytes($padlen, $padbuf);
674 $ret = $bstream->append($padding);
679 //----------------------------------------------------------------------
680 public function mergeBitStream()
682 if($this->convertData() < 0) {
686 $bstream = new QRbitstream();
688 foreach($this->items
as $item) {
689 $ret = $bstream->append($item->bstream
);
698 //----------------------------------------------------------------------
699 public function getBitStream()
702 $bstream = $this->mergeBitStream();
704 if($bstream == null) {
708 $ret = $this->appendPaddingBit($bstream);
716 //----------------------------------------------------------------------
717 public function getByteStream()
719 $bstream = $this->getBitStream();
720 if($bstream == null) {
724 return $bstream->toByte();