|
<?php |
|
|
|
namespace PHPQRCode; |
|
|
|
use Exception; |
|
|
|
class QRinputItem { |
|
|
|
public $mode; |
|
public $size; |
|
public $data; |
|
public $bstream; |
|
|
|
public function __construct($mode, $size, $data, $bstream = null) |
|
{ |
|
$setData = array_slice($data, 0, $size); |
|
|
|
if (count($setData) < $size) { |
|
$setData = array_merge($setData, array_fill(0,$size-count($setData),0)); |
|
} |
|
|
|
if(!QRinput::check($mode, $size, $setData)) { |
|
throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData)); |
|
return null; |
|
} |
|
|
|
$this->mode = $mode; |
|
$this->size = $size; |
|
$this->data = $setData; |
|
$this->bstream = $bstream; |
|
} |
|
|
|
|
|
public function encodeModeNum($version) |
|
{ |
|
try { |
|
|
|
$words = (int)($this->size / 3); |
|
$bs = new QRbitstream(); |
|
|
|
$val = 0x1; |
|
$bs->appendNum(4, $val); |
|
$bs->appendNum(QRspec::lengthIndicator(Constants::QR_MODE_NUM, $version), $this->size); |
|
|
|
for($i=0; $i<$words; $i++) { |
|
$val = (ord($this->data[$i*3 ]) - ord('0')) * 100; |
|
$val += (ord($this->data[$i*3+1]) - ord('0')) * 10; |
|
$val += (ord($this->data[$i*3+2]) - ord('0')); |
|
$bs->appendNum(10, $val); |
|
} |
|
|
|
if($this->size - $words * 3 == 1) { |
|
$val = ord($this->data[$words*3]) - ord('0'); |
|
$bs->appendNum(4, $val); |
|
} else if($this->size - $words * 3 == 2) { |
|
$val = (ord($this->data[$words*3 ]) - ord('0')) * 10; |
|
$val += (ord($this->data[$words*3+1]) - ord('0')); |
|
$bs->appendNum(7, $val); |
|
} |
|
|
|
$this->bstream = $bs; |
|
return 0; |
|
|
|
} catch (Exception $e) { |
|
return -1; |
|
} |
|
} |
|
|
|
|
|
public function encodeModeAn($version) |
|
{ |
|
try { |
|
$words = (int)($this->size / 2); |
|
$bs = new QRbitstream(); |
|
|
|
$bs->appendNum(4, 0x02); |
|
$bs->appendNum(QRspec::lengthIndicator(Constants::QR_MODE_AN, $version), $this->size); |
|
|
|
for($i=0; $i<$words; $i++) { |
|
$val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45; |
|
$val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1])); |
|
|
|
$bs->appendNum(11, $val); |
|
} |
|
|
|
if($this->size & 1) { |
|
$val = QRinput::lookAnTable(ord($this->data[$words * 2])); |
|
$bs->appendNum(6, $val); |
|
} |
|
|
|
$this->bstream = $bs; |
|
return 0; |
|
|
|
} catch (Exception $e) { |
|
return -1; |
|
} |
|
} |
|
|
|
|
|
public function encodeMode8($version) |
|
{ |
|
try { |
|
$bs = new QRbitstream(); |
|
|
|
$bs->appendNum(4, 0x4); |
|
$bs->appendNum(QRspec::lengthIndicator(Constants::QR_MODE_8, $version), $this->size); |
|
|
|
for($i=0; $i<$this->size; $i++) { |
|
$bs->appendNum(8, ord($this->data[$i])); |
|
} |
|
|
|
$this->bstream = $bs; |
|
return 0; |
|
|
|
} catch (Exception $e) { |
|
return -1; |
|
} |
|
} |
|
|
|
|
|
public function encodeModeKanji($version) |
|
{ |
|
try { |
|
|
|
$bs = new QRbitstream(); |
|
|
|
$bs->appendNum(4, 0x8); |
|
$bs->appendNum(QRspec::lengthIndicator(Constants::QR_MODE_KANJI, $version), (int)($this->size / 2)); |
|
|
|
for($i=0; $i<$this->size; $i+=2) { |
|
$val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]); |
|
if($val <= 0x9ffc) { |
|
$val -= 0x8140; |
|
} else { |
|
$val -= 0xc140; |
|
} |
|
|
|
$h = ($val >> 8) * 0xc0; |
|
$val = ($val & 0xff) + $h; |
|
|
|
$bs->appendNum(13, $val); |
|
} |
|
|
|
$this->bstream = $bs; |
|
return 0; |
|
|
|
} catch (Exception $e) { |
|
return -1; |
|
} |
|
} |
|
|
|
|
|
public function encodeModeStructure() |
|
{ |
|
try { |
|
$bs = new QRbitstream(); |
|
|
|
$bs->appendNum(4, 0x03); |
|
$bs->appendNum(4, ord($this->data[1]) - 1); |
|
$bs->appendNum(4, ord($this->data[0]) - 1); |
|
$bs->appendNum(8, ord($this->data[2])); |
|
|
|
$this->bstream = $bs; |
|
return 0; |
|
|
|
} catch (Exception $e) { |
|
return -1; |
|
} |
|
} |
|
|
|
|
|
public function estimateBitStreamSizeOfEntry($version) |
|
{ |
|
$bits = 0; |
|
|
|
if($version == 0) |
|
$version = 1; |
|
|
|
switch($this->mode) { |
|
case Constants::QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break; |
|
case Constants::QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break; |
|
case Constants::QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break; |
|
case Constants::QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break; |
|
case Constants::QR_MODE_STRUCTURE: return Constants::STRUCTURE_HEADER_BITS; |
|
default: |
|
return 0; |
|
} |
|
|
|
$l = QRspec::lengthIndicator($this->mode, $version); |
|
$m = 1 << $l; |
|
$num = (int)(($this->size + $m - 1) / $m); |
|
|
|
$bits += $num * (4 + $l); |
|
|
|
return $bits; |
|
} |
|
|
|
|
|
public function encodeBitStream($version) |
|
{ |
|
try { |
|
|
|
unset($this->bstream); |
|
$words = QRspec::maximumWords($this->mode, $version); |
|
|
|
if($this->size > $words) { |
|
|
|
$st1 = new QRinputItem($this->mode, $words, $this->data); |
|
$st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words)); |
|
|
|
$st1->encodeBitStream($version); |
|
$st2->encodeBitStream($version); |
|
|
|
$this->bstream = new QRbitstream(); |
|
$this->bstream->append($st1->bstream); |
|
$this->bstream->append($st2->bstream); |
|
|
|
unset($st1); |
|
unset($st2); |
|
|
|
} else { |
|
|
|
$ret = 0; |
|
|
|
switch($this->mode) { |
|
case Constants::QR_MODE_NUM: $ret = $this->encodeModeNum($version); break; |
|
case Constants::QR_MODE_AN: $ret = $this->encodeModeAn($version); break; |
|
case Constants::QR_MODE_8: $ret = $this->encodeMode8($version); break; |
|
case Constants::QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break; |
|
case Constants::QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break; |
|
|
|
default: |
|
break; |
|
} |
|
|
|
if($ret < 0) |
|
return -1; |
|
} |
|
|
|
return $this->bstream->size(); |
|
|
|
} catch (Exception $e) { |
|
return -1; |
|
} |
|
} |
|
} |
|
|