mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-08-31 04:28:03 +00:00
🛀 extract Mode
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Mode
|
||||
*
|
||||
* @filesource Mode.php
|
||||
* @created 19.11.2020
|
||||
* @package chillerlan\QRCode\Common
|
||||
* @author smiley <smiley@chillerlan.net>
|
||||
* @copyright 2020 smiley
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace chillerlan\QRCode\Common;
|
||||
|
||||
use chillerlan\QRCode\Data\{AlphaNum, Byte, Kanji, Number};
|
||||
use chillerlan\QRCode\QRCodeException;
|
||||
|
||||
/**
|
||||
* ISO 18004:2006, 6.4.1, Tables 2 and 3
|
||||
*/
|
||||
class Mode{
|
||||
|
||||
// ISO/IEC 18004:2000 Table 2
|
||||
|
||||
/** @var int */
|
||||
public const DATA_TERMINATOR = 0b0000;
|
||||
/** @var int */
|
||||
public const DATA_NUMBER = 0b0001;
|
||||
/** @var int */
|
||||
public const DATA_ALPHANUM = 0b0010;
|
||||
/** @var int */
|
||||
public const DATA_BYTE = 0b0100;
|
||||
/** @var int */
|
||||
public const DATA_KANJI = 0b1000;
|
||||
/** @var int */
|
||||
public const DATA_STRCTURED_APPEND = 0b0011;
|
||||
/** @var int */
|
||||
public const DATA_FNC1_FIRST = 0b0101;
|
||||
/** @var int */
|
||||
public const DATA_FNC1_SECOND = 0b1001;
|
||||
/** @var int */
|
||||
public const DATA_ECI = 0b0111;
|
||||
|
||||
/**
|
||||
* mode length bits for the version breakpoints 1-9, 10-26 and 27-40
|
||||
*
|
||||
* ISO/IEC 18004:2000 Table 3 - Number of bits in Character Count Indicator
|
||||
*/
|
||||
public const LENGTH_BITS = [
|
||||
self::DATA_NUMBER => [10, 12, 14],
|
||||
self::DATA_ALPHANUM => [9, 11, 13],
|
||||
self::DATA_BYTE => [8, 16, 16],
|
||||
self::DATA_KANJI => [8, 10, 12],
|
||||
];
|
||||
|
||||
/**
|
||||
* Map of data mode => interface (detection order)
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public const DATA_INTERFACES = [
|
||||
Mode::DATA_NUMBER => Number::class,
|
||||
Mode::DATA_ALPHANUM => AlphaNum::class,
|
||||
Mode::DATA_KANJI => Kanji::class,
|
||||
Mode::DATA_BYTE => Byte::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* returns the length bits for the version breakpoints 1-9, 10-26 and 27-40
|
||||
*
|
||||
* @throws \chillerlan\QRCode\QRCodeException
|
||||
*/
|
||||
public static function getLengthBitsForVersion(int $mode, int $version):int{
|
||||
|
||||
if(!isset(self::LENGTH_BITS[$mode])){
|
||||
throw new QRCodeException('invalid mode given');
|
||||
}
|
||||
|
||||
foreach([9, 26, 40] as $key => $breakpoint){
|
||||
if($version <= $breakpoint){
|
||||
return self::LENGTH_BITS[$mode][$key];
|
||||
}
|
||||
}
|
||||
|
||||
throw new QRCodeException(sprintf('invalid version number: %d', $version));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
|
||||
use function ceil, ord, sprintf, str_split;
|
||||
|
||||
@@ -39,7 +39,7 @@ final class AlphaNum extends QRDataModeAbstract{
|
||||
'+' => 40, '-' => 41, '.' => 42, '/' => 43, ':' => 44,
|
||||
];
|
||||
|
||||
protected array $lengthBits = [9, 11, 13];
|
||||
protected int $datamode = Mode::DATA_ALPHANUM;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@@ -69,8 +69,8 @@ final class AlphaNum extends QRDataModeAbstract{
|
||||
$len = $this->getCharCount();
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_ALPHANUM, 4)
|
||||
->put($len, $this->getLengthBitsForVersion($version))
|
||||
->put($this->datamode, 4)
|
||||
->put($len, Mode::getLengthBitsForVersion($this->datamode, $version))
|
||||
;
|
||||
|
||||
// encode 2 characters in 11 bits
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
|
||||
use function ord;
|
||||
|
||||
@@ -25,7 +25,7 @@ use function ord;
|
||||
*/
|
||||
final class Byte extends QRDataModeAbstract{
|
||||
|
||||
protected array $lengthBits = [8, 16, 16];
|
||||
protected int $datamode = Mode::DATA_BYTE;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@@ -48,8 +48,8 @@ final class Byte extends QRDataModeAbstract{
|
||||
$len = $this->getCharCount();
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_BYTE, 4)
|
||||
->put($len, $this->getLengthBitsForVersion($version))
|
||||
->put($this->datamode, 4)
|
||||
->put($len, Mode::getLengthBitsForVersion($this->datamode, $version))
|
||||
;
|
||||
|
||||
$i = 0;
|
||||
|
||||
+4
-2
@@ -13,7 +13,7 @@
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
|
||||
/**
|
||||
* Adds an ECI Designator
|
||||
@@ -59,6 +59,8 @@ class ECI extends QRDataModeAbstract{
|
||||
*/
|
||||
protected int $encoding;
|
||||
|
||||
protected int $datamode = Mode::DATA_ECI;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -87,7 +89,7 @@ class ECI extends QRDataModeAbstract{
|
||||
*/
|
||||
public function write(BitBuffer $bitBuffer, int $version):void{
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_ECI, 4)
|
||||
->put($this->datamode, 4)
|
||||
->put($this->encoding, 8)
|
||||
;
|
||||
}
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
|
||||
use function mb_convert_encoding, mb_detect_encoding, mb_strlen, ord, sprintf, strlen;
|
||||
|
||||
@@ -25,7 +25,7 @@ use function mb_convert_encoding, mb_detect_encoding, mb_strlen, ord, sprintf, s
|
||||
*/
|
||||
final class Kanji extends QRDataModeAbstract{
|
||||
|
||||
protected array $lengthBits = [8, 10, 12];
|
||||
protected int $datamode = Mode::DATA_KANJI;
|
||||
|
||||
public function __construct(string $data){
|
||||
parent::__construct($data);
|
||||
@@ -76,8 +76,8 @@ final class Kanji extends QRDataModeAbstract{
|
||||
public function write(BitBuffer $bitBuffer, int $version):void{
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_KANJI, 4)
|
||||
->put($this->getCharCount(), $this->getLengthBitsForVersion($version))
|
||||
->put($this->datamode, 4)
|
||||
->put($this->getCharCount(), Mode::getLengthBitsForVersion($this->datamode, $version))
|
||||
;
|
||||
|
||||
$len = strlen($this->data);
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
|
||||
use function ceil, ord, sprintf, str_split, substr;
|
||||
|
||||
@@ -32,7 +32,7 @@ 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 array $lengthBits = [10, 12, 14];
|
||||
protected int $datamode = Mode::DATA_NUMBER;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@@ -62,8 +62,8 @@ final class Number extends QRDataModeAbstract{
|
||||
$len = $this->getCharCount();
|
||||
|
||||
$bitBuffer
|
||||
->put(QRCode::DATA_NUMBER, 4)
|
||||
->put($len, $this->getLengthBitsForVersion($version))
|
||||
->put($this->datamode, 4)
|
||||
->put($len, Mode::getLengthBitsForVersion($this->datamode, $version))
|
||||
;
|
||||
|
||||
$i = 0;
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Helpers\{BitBuffer, Polynomial};
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
use chillerlan\Settings\SettingsContainerInterface;
|
||||
|
||||
use function array_column, array_combine, array_fill, array_keys, array_merge, count, max, range, sprintf;
|
||||
@@ -221,7 +222,7 @@ class QRData{
|
||||
|
||||
foreach($this->dataSegments as $segment){
|
||||
// data length in bits of the current segment +4 bits for each mode descriptor
|
||||
$length += ($segment->getLengthInBits() + $segment->getLengthBits(0) + 4);
|
||||
$length += ($segment->getLengthInBits() + Mode::LENGTH_BITS[$segment->getDataMode()][0] + 4);
|
||||
|
||||
if(!$segment instanceof ECI){
|
||||
// mode length bits margin to the next breakpoint
|
||||
|
||||
@@ -12,18 +12,14 @@
|
||||
|
||||
namespace chillerlan\QRCode\Data;
|
||||
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
|
||||
/**
|
||||
*/
|
||||
abstract class QRDataModeAbstract implements QRDataModeInterface{
|
||||
|
||||
/**
|
||||
* mode length bits for the version breakpoints 1-9, 10-26 and 27-40
|
||||
*
|
||||
* ISO/IEC 18004:2000 Table 3 - Number of bits in Character Count Indicator
|
||||
* the current data mode: Num, Alphanum, Kanji, Byte
|
||||
*/
|
||||
protected array $lengthBits = [0, 0, 0];
|
||||
protected int $datamode;
|
||||
|
||||
/**
|
||||
* The data to write
|
||||
@@ -34,7 +30,7 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
|
||||
* QRDataModeAbstract constructor.
|
||||
*/
|
||||
public function __construct(string $data){
|
||||
$this->data = $data;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,25 +43,8 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getLengthBits(int $k):int{
|
||||
return $this->lengthBits[$k] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the length bits for the version breakpoints 1-9, 10-26 and 27-40
|
||||
*
|
||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function getLengthBitsForVersion(int $version):int{
|
||||
|
||||
foreach([9, 26, 40] as $key => $breakpoint){
|
||||
if($version <= $breakpoint){
|
||||
return $this->getLengthBits($key);
|
||||
}
|
||||
}
|
||||
|
||||
throw new QRCodeDataException(sprintf('invalid version number: %d', $version));
|
||||
public function getDataMode():int{
|
||||
return $this->datamode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
interface QRDataModeInterface{
|
||||
|
||||
/**
|
||||
* returns the length bits for the given breakpoint [0,1,2]
|
||||
* returns the current data mode constant
|
||||
*/
|
||||
public function getLengthBits(int $k):int;
|
||||
public function getDataMode():int;
|
||||
|
||||
/**
|
||||
* retruns the length in bits of the data string
|
||||
|
||||
+2
-26
@@ -13,6 +13,7 @@
|
||||
namespace chillerlan\QRCode;
|
||||
|
||||
use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, MaskPatternTester, Number, QRData, QRCodeDataException, QRMatrix};
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
use chillerlan\QRCode\Output\{
|
||||
QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString
|
||||
};
|
||||
@@ -36,19 +37,6 @@ class QRCode{
|
||||
/** @var int */
|
||||
public const MASK_PATTERN_AUTO = -1;
|
||||
|
||||
// ISO/IEC 18004:2000 Table 2
|
||||
|
||||
/** @var int */
|
||||
public const DATA_NUMBER = 0b0001;
|
||||
/** @var int */
|
||||
public const DATA_ALPHANUM = 0b0010;
|
||||
/** @var int */
|
||||
public const DATA_BYTE = 0b0100;
|
||||
/** @var int */
|
||||
public const DATA_KANJI = 0b1000;
|
||||
/** @var int */
|
||||
public const DATA_ECI = 0b0111;
|
||||
|
||||
// ISO/IEC 18004:2000 Tables 12, 25
|
||||
|
||||
/** @var int */
|
||||
@@ -124,18 +112,6 @@ class QRCode{
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Map of data mode => interface (detection order)
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected const DATA_INTERFACES = [
|
||||
self::DATA_NUMBER => Number::class,
|
||||
self::DATA_ALPHANUM => AlphaNum::class,
|
||||
self::DATA_KANJI => Kanji::class,
|
||||
self::DATA_BYTE => Byte::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* A collection of one or more data segments of [classname, data] to write
|
||||
*
|
||||
@@ -175,7 +151,7 @@ class QRCode{
|
||||
|
||||
if($data !== null){
|
||||
/** @var \chillerlan\QRCode\Data\QRDataModeInterface $dataInterface */
|
||||
foreach($this::DATA_INTERFACES as $dataInterface){
|
||||
foreach(Mode::DATA_INTERFACES as $dataInterface){
|
||||
|
||||
if($dataInterface::validateString($data)){
|
||||
$this->addSegment($data, $dataInterface);
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
namespace chillerlan\QRCodeTest\Helpers;
|
||||
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\Helpers\BitBuffer;
|
||||
use chillerlan\QRCode\Common\Mode;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
@@ -29,10 +29,10 @@ final class BitBufferTest extends TestCase{
|
||||
|
||||
public function bitProvider():array{
|
||||
return [
|
||||
'number' => [QRCode::DATA_NUMBER, 16],
|
||||
'alphanum' => [QRCode::DATA_ALPHANUM, 32],
|
||||
'byte' => [QRCode::DATA_BYTE, 64],
|
||||
'kanji' => [QRCode::DATA_KANJI, 128],
|
||||
'number' => [Mode::DATA_NUMBER, 16],
|
||||
'alphanum' => [Mode::DATA_ALPHANUM, 32],
|
||||
'byte' => [Mode::DATA_BYTE, 64],
|
||||
'kanji' => [Mode::DATA_KANJI, 128],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user