mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-08-30 03:58:28 +00:00
🛀 data mode rework
This commit is contained in:
+13
-8
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
|
||||
use function ceil, ord, sprintf, str_split;
|
||||
@@ -38,15 +39,13 @@ final class AlphaNum extends QRDataModeAbstract{
|
||||
'+' => 40, '-' => 41, '.' => 42, '/' => 43, ':' => 44,
|
||||
];
|
||||
|
||||
protected int $datamode = QRCode::DATA_ALPHANUM;
|
||||
|
||||
protected array $lengthBits = [9, 11, 13];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLengthInBits():int{
|
||||
return (int)ceil($this->getLength() * (11 / 2));
|
||||
return (int)ceil($this->getCharCount() * (11 / 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,16 +65,22 @@ final class AlphaNum extends QRDataModeAbstract{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function write(int $version):void{
|
||||
$this->writeSegmentHeader($version);
|
||||
$len = $this->getLength();
|
||||
public function write(BitBuffer $bitBuffer, int $version):void{
|
||||
$len = $this->getCharCount();
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_ALPHANUM, 4)
|
||||
->put($len, $this->getLengthBitsForVersion($version))
|
||||
;
|
||||
|
||||
// encode 2 characters in 11 bits
|
||||
for($i = 0; $i + 1 < $len; $i += 2){
|
||||
$this->bitBuffer->put($this->getCharCode($this->data[$i]) * 45 + $this->getCharCode($this->data[$i + 1]), 11);
|
||||
$bitBuffer->put($this->getCharCode($this->data[$i]) * 45 + $this->getCharCode($this->data[$i + 1]), 11);
|
||||
}
|
||||
|
||||
// encode a remaining character in 6 bits
|
||||
if($i < $len){
|
||||
$this->bitBuffer->put($this->getCharCode($this->data[$i]), 6);
|
||||
$bitBuffer->put($this->getCharCode($this->data[$i]), 6);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-8
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
|
||||
use function ord;
|
||||
@@ -24,15 +25,13 @@ use function ord;
|
||||
*/
|
||||
final class Byte extends QRDataModeAbstract{
|
||||
|
||||
protected int $datamode = QRCode::DATA_BYTE;
|
||||
|
||||
protected array $lengthBits = [8, 16, 16];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLengthInBits():int{
|
||||
return $this->getLength() * 8;
|
||||
return $this->getCharCount() * 8;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,13 +44,18 @@ final class Byte extends QRDataModeAbstract{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function write(int $version):void{
|
||||
$this->writeSegmentHeader($version);
|
||||
$len = $this->getLength();
|
||||
$i = 0;
|
||||
public function write(BitBuffer $bitBuffer, int $version):void{
|
||||
$len = $this->getCharCount();
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_BYTE, 4)
|
||||
->put($len, $this->getLengthBitsForVersion($version))
|
||||
;
|
||||
|
||||
$i = 0;
|
||||
|
||||
while($i < $len){
|
||||
$this->bitBuffer->put(ord($this->data[$i]), 8);
|
||||
$bitBuffer->put(ord($this->data[$i]), 8);
|
||||
$i++;
|
||||
}
|
||||
|
||||
|
||||
+13
-11
@@ -25,12 +25,10 @@ use function mb_convert_encoding, mb_detect_encoding, mb_strlen, ord, sprintf, s
|
||||
*/
|
||||
final class Kanji extends QRDataModeAbstract{
|
||||
|
||||
protected int $datamode = QRCode::DATA_KANJI;
|
||||
|
||||
protected array $lengthBits = [8, 10, 12];
|
||||
|
||||
public function __construct(BitBuffer $bitBuffer, string $data){
|
||||
parent::__construct($bitBuffer, $data);
|
||||
public function __construct(string $data){
|
||||
parent::__construct($data);
|
||||
|
||||
/** @noinspection PhpFieldAssignmentTypeMismatchInspection */
|
||||
$this->data = mb_convert_encoding($this->data, 'SJIS', mb_detect_encoding($this->data));
|
||||
@@ -39,7 +37,7 @@ final class Kanji extends QRDataModeAbstract{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getLength():int{
|
||||
protected function getCharCount():int{
|
||||
return mb_strlen($this->data, 'SJIS');
|
||||
}
|
||||
|
||||
@@ -47,7 +45,7 @@ final class Kanji extends QRDataModeAbstract{
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLengthInBits():int{
|
||||
return $this->getLength() * 13;
|
||||
return $this->getCharCount() * 13;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,9 +73,14 @@ final class Kanji extends QRDataModeAbstract{
|
||||
*
|
||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException on an illegal character occurence
|
||||
*/
|
||||
public function write(int $version):void{
|
||||
$this->writeSegmentHeader($version);
|
||||
$len = strlen($this->data); // not self::getLength() - we need 8-bit length
|
||||
public function write(BitBuffer $bitBuffer, int $version):void{
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_KANJI, 4)
|
||||
->put($this->getCharCount(), $this->getLengthBitsForVersion($version))
|
||||
;
|
||||
|
||||
$len = strlen($this->data);
|
||||
|
||||
for($i = 0; $i + 1 < $len; $i += 2){
|
||||
$c = ((0xff & ord($this->data[$i])) << 8) | (0xff & ord($this->data[$i + 1]));
|
||||
@@ -92,8 +95,7 @@ final class Kanji extends QRDataModeAbstract{
|
||||
throw new QRCodeDataException(sprintf('illegal char at %d [%d]', $i + 1, $c));
|
||||
}
|
||||
|
||||
$this->bitBuffer->put(((($c >> 8) & 0xff) * 0xC0) + ($c & 0xff), 13);
|
||||
|
||||
$bitBuffer->put(((($c >> 8) & 0xff) * 0xC0) + ($c & 0xff), 13);
|
||||
}
|
||||
|
||||
if($i < $len){
|
||||
|
||||
+19
-12
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
|
||||
use function ceil, ord, sprintf, str_split, substr;
|
||||
@@ -31,15 +32,13 @@ final class Number extends QRDataModeAbstract{
|
||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
|
||||
];
|
||||
|
||||
protected int $datamode = QRCode::DATA_NUMBER;
|
||||
|
||||
protected array $lengthBits = [10, 12, 14];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLengthInBits():int{
|
||||
return (int)ceil($this->getLength() * (10 / 3));
|
||||
return (int)ceil($this->getCharCount() * (10 / 3));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,23 +58,31 @@ final class Number extends QRDataModeAbstract{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function write(int $version):void{
|
||||
$this->writeSegmentHeader($version);
|
||||
$len = $this->getLength();
|
||||
$i = 0;
|
||||
public function write(BitBuffer $bitBuffer, int $version):void{
|
||||
$len = $this->getCharCount();
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_NUMBER, 4)
|
||||
->put($len, $this->getLengthBitsForVersion($version))
|
||||
;
|
||||
|
||||
$i = 0;
|
||||
|
||||
// encode numeric triplets in 10 bits
|
||||
while($i + 2 < $len){
|
||||
$this->bitBuffer->put($this->parseInt(substr($this->data, $i, 3)), 10);
|
||||
$bitBuffer->put($this->parseInt(substr($this->data, $i, 3)), 10);
|
||||
$i += 3;
|
||||
}
|
||||
|
||||
if($i < $len){
|
||||
|
||||
if($len - $i === 1){
|
||||
$this->bitBuffer->put($this->parseInt(substr($this->data, $i, $i + 1)), 4);
|
||||
// encode 2 remaining numbers in 7 bits
|
||||
if($len - $i === 2){
|
||||
$bitBuffer->put($this->parseInt(substr($this->data, $i, 2)), 7);
|
||||
}
|
||||
elseif($len - $i === 2){
|
||||
$this->bitBuffer->put($this->parseInt(substr($this->data, $i, $i + 2)), 7);
|
||||
// encode one remaining number in 4 bits
|
||||
elseif($len - $i === 1){
|
||||
$bitBuffer->put($this->parseInt(substr($this->data, $i, 1)), 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -188,7 +188,7 @@ class QRData{
|
||||
foreach($dataSegments as $segment){
|
||||
[$class, $data] = $segment;
|
||||
|
||||
$this->dataSegments[] = new $class($this->bitBuffer, $data);
|
||||
$this->dataSegments[] = new $class($data);
|
||||
}
|
||||
|
||||
$this->version = $this->options->version === QRCode::VERSION_AUTO
|
||||
@@ -271,7 +271,7 @@ class QRData{
|
||||
$MAX_BITS = $this->maxBitsForEcc[$this->version];
|
||||
|
||||
foreach($this->dataSegments as $segment){
|
||||
$segment->write($this->version);
|
||||
$segment->write($this->bitBuffer, $this->version);
|
||||
}
|
||||
|
||||
// overflow, likely caused due to invalid version setting
|
||||
|
||||
@@ -18,11 +18,6 @@ use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
*/
|
||||
abstract class QRDataModeAbstract implements QRDataModeInterface{
|
||||
|
||||
/**
|
||||
* the current data mode: Num, Alphanum, Kanji, Byte
|
||||
*/
|
||||
protected int $datamode;
|
||||
|
||||
/**
|
||||
* mode length bits for the version breakpoints 1-9, 10-26 and 27-40
|
||||
*
|
||||
@@ -35,30 +30,17 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
|
||||
*/
|
||||
protected string $data;
|
||||
|
||||
/**
|
||||
* a BitBuffer instance
|
||||
*/
|
||||
protected BitBuffer $bitBuffer;
|
||||
|
||||
/**
|
||||
* QRDataModeAbstract constructor.
|
||||
*
|
||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||
*/
|
||||
public function __construct(BitBuffer $bitBuffer, string $data){
|
||||
// do we need this here? we check during write anyways.
|
||||
# if(!static::validateString($data)){
|
||||
# throw new QRCodeDataException('invalid data string');
|
||||
# }
|
||||
|
||||
$this->bitBuffer = $bitBuffer;
|
||||
public function __construct(string $data){
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the character count of the $data string
|
||||
*/
|
||||
protected function getLength():int{
|
||||
protected function getCharCount():int{
|
||||
return strlen($this->data);
|
||||
}
|
||||
|
||||
@@ -86,16 +68,4 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
|
||||
throw new QRCodeDataException(sprintf('invalid version number: %d', $version));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function writeSegmentHeader(int $version):void{
|
||||
|
||||
$this->bitBuffer
|
||||
->put($this->datamode, 4)
|
||||
->put($this->getLength(), $this->getLengthBitsForVersion($version))
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
|
||||
/**
|
||||
* Specifies the methods reqired for the data modules (Number, Alphanum, Byte and Kanji)
|
||||
* and holds version information in several constants
|
||||
@@ -38,6 +40,6 @@ interface QRDataModeInterface{
|
||||
*
|
||||
* @see \chillerlan\QRCode\Data\QRData::writeBitBuffer()
|
||||
*/
|
||||
public function write(int $version):void;
|
||||
public function write(BitBuffer $bitBuffer, int $version):void;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user