|
|
@@ -12,13 +12,7 @@
|
|
|
|
|
|
namespace codemasher\QRCode;
|
|
|
|
|
|
-use codemasher\QRCode\Polynomial;
|
|
|
-use codemasher\QRCode\QRConst;
|
|
|
-use codemasher\QRCode\Data\AlphaNum;
|
|
|
-use codemasher\QRCode\Data\Byte;
|
|
|
-use codemasher\QRCode\Data\Kanji;
|
|
|
-use codemasher\QRCode\Data\Number;
|
|
|
-use codemasher\QRCode\Data\QRDataInterface;
|
|
|
+use codemasher\QRCode\Data\QRDataBase;
|
|
|
|
|
|
/**
|
|
|
* @link https://github.com/kazuhikoarase/qrcode-generator/tree/master/php
|
|
|
@@ -31,25 +25,25 @@ class QRCode{
|
|
|
/**
|
|
|
* @var int
|
|
|
*/
|
|
|
- public $typeNumber;
|
|
|
+ public $moduleCount;
|
|
|
|
|
|
/**
|
|
|
* @var array
|
|
|
*/
|
|
|
- protected $modules;
|
|
|
+ public $modules;
|
|
|
|
|
|
/**
|
|
|
* @var int
|
|
|
*/
|
|
|
- public $moduleCount;
|
|
|
+ protected $typeNumber;
|
|
|
|
|
|
/**
|
|
|
* @var int
|
|
|
*/
|
|
|
- public $errorCorrectLevel;
|
|
|
+ protected $errorCorrectLevel;
|
|
|
|
|
|
/**
|
|
|
- * @var array
|
|
|
+ * @var array -> \codemasher\QRCode\Data\QRDataInterface
|
|
|
*/
|
|
|
protected $qrDataList = [];
|
|
|
|
|
|
@@ -63,6 +57,31 @@ class QRCode{
|
|
|
*/
|
|
|
protected $data;
|
|
|
|
|
|
+ /**
|
|
|
+ * @var int
|
|
|
+ */
|
|
|
+ protected $mode;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @var array
|
|
|
+ */
|
|
|
+ protected $ERROR_CORRECT_LEVEL = [
|
|
|
+ QRConst::ERROR_CORRECT_LEVEL_L,
|
|
|
+ QRConst::ERROR_CORRECT_LEVEL_M,
|
|
|
+ QRConst::ERROR_CORRECT_LEVEL_Q,
|
|
|
+ QRConst::ERROR_CORRECT_LEVEL_H,
|
|
|
+ ];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @var array
|
|
|
+ */
|
|
|
+ protected $qrDataInterface = [
|
|
|
+ QRConst::MODE_ALPHANUM => '\\codemasher\\QRCode\\Data\\AlphaNum',
|
|
|
+ QRConst::MODE_BYTE => '\\codemasher\\QRCode\\Data\\Byte',
|
|
|
+ QRConst::MODE_KANJI => '\\codemasher\\QRCode\\Data\\Kanji',
|
|
|
+ QRConst::MODE_NUMBER => '\\codemasher\\QRCode\\Data\\Number',
|
|
|
+ ];
|
|
|
+
|
|
|
/**
|
|
|
* @var \codemasher\QRCode\Util
|
|
|
*/
|
|
|
@@ -79,23 +98,63 @@ class QRCode{
|
|
|
protected $bitBuffer;
|
|
|
|
|
|
/**
|
|
|
+ * @todo WIP
|
|
|
+ *
|
|
|
* QRCode constructor.
|
|
|
*
|
|
|
- * @param int $typeNumber
|
|
|
- * @param int $errorCorrectLevel
|
|
|
+ * @param string $data
|
|
|
+ * @param int $errorCorrectLevel
|
|
|
+ * @param int $typeNumber
|
|
|
+ *
|
|
|
+ * @throws \codemasher\QRCode\QRCodeException
|
|
|
*/
|
|
|
- public function __construct($typeNumber = 1, $errorCorrectLevel = QRConst::ERROR_CORRECT_LEVEL_H){
|
|
|
+ public function __construct($data = '', $errorCorrectLevel = QRConst::ERROR_CORRECT_LEVEL_M, $typeNumber = null){
|
|
|
$this->util = new Util;
|
|
|
$this->rsBlock = new RSBlock;
|
|
|
$this->bitBuffer = new BitBuffer;
|
|
|
|
|
|
- $this->typeNumber = $typeNumber;
|
|
|
- $this->errorCorrectLevel = $errorCorrectLevel;
|
|
|
+ $this->setErrorCorrectLevel($errorCorrectLevel)->setTypeNumber($typeNumber);
|
|
|
+
|
|
|
+ if(!empty($data)){
|
|
|
+ $this->getMinimumQRCode($data);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @todo WIP
|
|
|
+ *
|
|
|
+ * @param $data
|
|
|
+ *
|
|
|
+ * @return \codemasher\QRCode\QRCode
|
|
|
+ * @throws \codemasher\QRCode\QRCodeException
|
|
|
+ */
|
|
|
+ public function getMinimumQRCode($data){
|
|
|
+ $mode = $this->util->getMode($data);
|
|
|
+ $this->addData($data, $mode);
|
|
|
+
|
|
|
+ /** @var \codemasher\QRCode\Data\QRDataBase $qrData */
|
|
|
+ $qrData = $this->qrDataList[0];
|
|
|
+ $length = $qrData->mode === QRConst::MODE_KANJI ? floor($qrData->dataLength / 2) : $qrData->dataLength;
|
|
|
+
|
|
|
+ for($typeNumber = 1; $typeNumber <= 10; $typeNumber++){
|
|
|
+ if($length <= $this->util->getMaxLength($typeNumber, $mode, $this->errorCorrectLevel)){
|
|
|
+ $this->typeNumber = $typeNumber;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->make();
|
|
|
+
|
|
|
+ return $this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * @todo WIP
|
|
|
+ *
|
|
|
* @param string $data
|
|
|
- * @param int $mode
|
|
|
+ *
|
|
|
+ * @param null $mode
|
|
|
*
|
|
|
* @return $this
|
|
|
* @throws \codemasher\QRCode\QRCodeException
|
|
|
@@ -105,77 +164,174 @@ class QRCode{
|
|
|
$mode = $this->util->getMode($data);
|
|
|
}
|
|
|
|
|
|
- switch($mode){
|
|
|
- case QRConst::MODE_NUMBER : $this->qrDataList[] = new Number($data); break;
|
|
|
- case QRConst::MODE_ALPHANUM: $this->qrDataList[] = new AlphaNum($data); break;
|
|
|
- case QRConst::MODE_BYTE : $this->qrDataList[] = new Byte($data); break;
|
|
|
- case QRConst::MODE_KANJI : $this->qrDataList[] = new Kanji($data); break;
|
|
|
- default:
|
|
|
- throw new QRCodeException('mode: '.$mode);
|
|
|
+ if(!isset($this->qrDataInterface[$mode])){
|
|
|
+ throw new QRCodeException('mode: '.$mode);
|
|
|
}
|
|
|
|
|
|
+ $this->qrDataList[] = new $this->qrDataInterface[$mode]($data);
|
|
|
+
|
|
|
return $this;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * @param int $row
|
|
|
- * @param int $col
|
|
|
+ * @param $errorCorrectLevel
|
|
|
*
|
|
|
- * @return bool
|
|
|
+ * @return $this
|
|
|
+ * @throws \codemasher\QRCode\QRCodeException
|
|
|
*/
|
|
|
- public function isDark($row, $col){
|
|
|
- if($this->modules[$row][$col] !== null){
|
|
|
- return (bool)$this->modules[$row][$col];
|
|
|
- }
|
|
|
- else{
|
|
|
- return false;
|
|
|
+ public function setErrorCorrectLevel($errorCorrectLevel){
|
|
|
+
|
|
|
+ if(!in_array($errorCorrectLevel, $this->ERROR_CORRECT_LEVEL)){
|
|
|
+ throw new QRCodeException('Invalid error correct level: '.$errorCorrectLevel);
|
|
|
}
|
|
|
+
|
|
|
+ $this->errorCorrectLevel = $errorCorrectLevel;
|
|
|
+
|
|
|
+ return $this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * @param int $typeNumber
|
|
|
*
|
|
|
+ * @return $this
|
|
|
+ * @throws \codemasher\QRCode\QRCodeException
|
|
|
*/
|
|
|
- public function make(){
|
|
|
- $this->makeImpl(false, $this->getBestMaskPattern());
|
|
|
+ public function setTypeNumber($typeNumber){
|
|
|
+ $typeNumber = intval($typeNumber);
|
|
|
+
|
|
|
+ if($typeNumber < 1 || $typeNumber > 10){
|
|
|
+ throw new QRCodeException('Invalid type number: '.$typeNumber);
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->typeNumber = $typeNumber;
|
|
|
|
|
|
return $this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @param $data
|
|
|
- * @param $errorCorrectLevel
|
|
|
*
|
|
|
- * @return \codemasher\QRCode\QRCode
|
|
|
- * @throws \codemasher\QRCode\QRCodeException
|
|
|
*/
|
|
|
- public function getMinimumQRCode($data, $errorCorrectLevel = QRConst::ERROR_CORRECT_LEVEL_H){
|
|
|
- $mode = $this->util->getMode($data);
|
|
|
- $this->addData($data, $mode);
|
|
|
- $this->errorCorrectLevel = $errorCorrectLevel;
|
|
|
+ public function make(){
|
|
|
+ $minLostPoint = 0;
|
|
|
+ $pattern = 0;
|
|
|
|
|
|
- /** @var \codemasher\QRCode\Data\QRDataBase $qrData */
|
|
|
- $qrData = $this->qrDataList[0];
|
|
|
- $length = $qrData->mode === QRConst::MODE_KANJI ? floor($qrData->dataLength / 2) : $qrData->dataLength;
|
|
|
+ for($i = 0; $i < 8; $i++){
|
|
|
+ $this->makeImpl(true, $i);
|
|
|
+ $lostPoint = 0;
|
|
|
|
|
|
- for($typeNumber = 1; $typeNumber <= 10; $typeNumber++){
|
|
|
- if($length <= $this->util->getMaxLength($typeNumber, $mode, $this->errorCorrectLevel)){
|
|
|
- $this->typeNumber = $typeNumber;
|
|
|
- break;
|
|
|
+ // LEVEL1
|
|
|
+ for($row = 0; $row < $this->moduleCount; $row++){
|
|
|
+ for($col = 0; $col < $this->moduleCount; $col++){
|
|
|
+ $sameCount = 0;
|
|
|
+ $dark = $this->modules[$row][$col];
|
|
|
+
|
|
|
+ for($r = -1; $r <= 1; $r++){
|
|
|
+ if($row + $r < 0 || $this->moduleCount <= $row + $r){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ for($c = -1; $c <= 1; $c++){
|
|
|
+
|
|
|
+ if(($r === 0 && $c === 0) || ($col + $c < 0 || $this->moduleCount <= $col + $c)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if($this->modules[$row + $r][$col + $c] === $dark){
|
|
|
+ $sameCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if($sameCount > 5){
|
|
|
+ $lostPoint += (3 + $sameCount - 5);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // LEVEL2
|
|
|
+ for($row = 0; $row < $this->moduleCount - 1; $row++){
|
|
|
+ for($col = 0; $col < $this->moduleCount - 1; $col++){
|
|
|
+ $count = 0;
|
|
|
+
|
|
|
+ if($this->modules[$row][$col] || $this->modules[$row][$col + 1]
|
|
|
+ || $this->modules[$row + 1][$col] || $this->modules[$row + 1][$col + 1]
|
|
|
+ ){
|
|
|
+ $count++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if($count === 0 || $count === 4){
|
|
|
+ $lostPoint += 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ // LEVEL3
|
|
|
+ for($row = 0; $row < $this->moduleCount; $row++){
|
|
|
+ for($col = 0; $col < $this->moduleCount - 6; $col++){
|
|
|
+ if($this->modules[$row][$col]
|
|
|
+ && !$this->modules[$row][$col + 1]
|
|
|
+ && $this->modules[$row][$col + 2]
|
|
|
+ && $this->modules[$row][$col + 3]
|
|
|
+ && $this->modules[$row][$col + 4]
|
|
|
+ && !$this->modules[$row][$col + 5]
|
|
|
+ && $this->modules[$row][$col + 6]
|
|
|
+ ){
|
|
|
+ $lostPoint += 40;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for($col = 0; $col < $this->moduleCount; $col++){
|
|
|
+ for($row = 0; $row < $this->moduleCount - 6; $row++){
|
|
|
+ if($this->modules[$row][$col]
|
|
|
+ && !$this->modules[$row + 1][$col]
|
|
|
+ && $this->modules[$row + 2][$col]
|
|
|
+ && $this->modules[$row + 3][$col]
|
|
|
+ && $this->modules[$row + 4][$col]
|
|
|
+ && !$this->modules[$row + 5][$col]
|
|
|
+ && $this->modules[$row + 6][$col]
|
|
|
+ ){
|
|
|
+ $lostPoint += 40;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // LEVEL4
|
|
|
+ $darkCount = 0;
|
|
|
+ for($col = 0; $col < $this->moduleCount; $col++){
|
|
|
+ for($row = 0; $row < $this->moduleCount; $row++){
|
|
|
+ if($this->modules[$row][$col]){
|
|
|
+ $darkCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $ratio = abs(100 * $darkCount / $this->moduleCount / $this->moduleCount - 50) / 5;
|
|
|
+ $lostPoint += $ratio * 10;
|
|
|
+
|
|
|
+ if($i === 0 || $minLostPoint > $lostPoint){
|
|
|
+ $minLostPoint = $lostPoint;
|
|
|
+ $pattern = $i;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- $this->makeImpl(false, $this->getBestMaskPattern());
|
|
|
+ $this->makeImpl(false, $pattern);
|
|
|
|
|
|
return $this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param bool $test
|
|
|
- * @param int $maskPattern
|
|
|
+ * @param int $pattern
|
|
|
*
|
|
|
* @return $this
|
|
|
+ * @throws \codemasher\QRCode\QRCodeException
|
|
|
*/
|
|
|
- protected function makeImpl($test, $maskPattern){
|
|
|
+ protected function makeImpl($test, $pattern){
|
|
|
$this->moduleCount = $this->typeNumber * 4 + 17;
|
|
|
$this->modules = [];
|
|
|
|
|
|
@@ -186,15 +342,41 @@ class QRCode{
|
|
|
|
|
|
$this->setupPositionProbePattern(0, 0)
|
|
|
->setupPositionProbePattern($this->moduleCount - 7, 0)
|
|
|
- ->setupPositionProbePattern(0, $this->moduleCount - 7)
|
|
|
- ->setupPositionAdjustPattern()
|
|
|
- ->setupTimingPattern();
|
|
|
+ ->setupPositionProbePattern(0, $this->moduleCount - 7);
|
|
|
+
|
|
|
+ // setupPositionAdjustPattern
|
|
|
+ $pos = $this->util->PATTERN_POSITION[$this->typeNumber - 1];
|
|
|
+ foreach($pos as $i => $posI){
|
|
|
+ foreach($pos as $j => $posJ){
|
|
|
+ if($this->modules[$posI][$posJ] !== null){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- $data = ($this->errorCorrectLevel << 3) | $maskPattern;
|
|
|
+ for($row = -2; $row <= 2; $row++){
|
|
|
+ for($col = -2; $col <= 2; $col++){
|
|
|
+ $this->modules[$posI + $row][$posJ + $col] =
|
|
|
+ (bool)$row === -2 || $row === 2 || $col === -2 || $col === 2 || ($row === 0 && $col === 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // setupTimingPattern
|
|
|
+ for($i = 8; $i < $this->moduleCount - 8; $i++){
|
|
|
+ if($this->modules[$i][6] !== null){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->modules[$i][6] = $this->modules[6][$i] = (bool)$i % 2 === 0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ $data = ($this->errorCorrectLevel << 3) | $pattern;
|
|
|
$bits = $this->util->getBCHTypeInfo($data);
|
|
|
|
|
|
for($i = 0; $i < 15; $i++){
|
|
|
- $mod = !$test && (($bits >> $i) & 1) === 1;
|
|
|
+ $mod = (bool)!$test && (($bits >> $i) & 1) === 1;
|
|
|
|
|
|
switch(true){
|
|
|
case $i < 6: $this->modules[$i][8] = $mod; break;
|
|
|
@@ -221,23 +403,12 @@ class QRCode{
|
|
|
$a = (int)floor($i / 3);
|
|
|
$b = $i % 3 + $this->moduleCount - 8 - 3;
|
|
|
|
|
|
- $this->modules[$a][$b] = $this->modules[$b][$a] = !$test && (($bits >> $i) & 1) === 1;
|
|
|
+ $this->modules[$a][$b] = $this->modules[$b][$a] = (bool)!$test && (($bits >> $i) & 1) === 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
$this->data = $this->createData($this->typeNumber, $this->errorCorrectLevel);
|
|
|
- $this->mapData($maskPattern);
|
|
|
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param $maskPattern
|
|
|
- *
|
|
|
- * @return $this
|
|
|
- * @throws \codemasher\QRCode\QRCodeException
|
|
|
- */
|
|
|
- protected function mapData($maskPattern){
|
|
|
$inc = -1;
|
|
|
$row = $this->moduleCount - 1;
|
|
|
$bitIndex = 7;
|
|
|
@@ -261,24 +432,27 @@ class QRCode{
|
|
|
}
|
|
|
|
|
|
$_col = $col - $c;
|
|
|
- switch($maskPattern){
|
|
|
- case QRConst::MASK_PATTERN000: $mask = ($row + $_col) % 2 === 0; break;
|
|
|
- case QRConst::MASK_PATTERN001: $mask = $row % 2 === 0; break;
|
|
|
- case QRConst::MASK_PATTERN010: $mask = $_col % 3 === 0; break;
|
|
|
- case QRConst::MASK_PATTERN011: $mask = ($row + $_col) % 3 === 0; break;
|
|
|
- case QRConst::MASK_PATTERN100: $mask = (floor($row / 2) + floor($_col / 3)) % 2 === 0; break;
|
|
|
- case QRConst::MASK_PATTERN101: $mask = ($row * $_col) % 2 + ($row * $_col) % 3 === 0; break;
|
|
|
- case QRConst::MASK_PATTERN110: $mask = (($row * $_col) % 2 + ($row * $_col) % 3) % 2 === 0; break;
|
|
|
- case QRConst::MASK_PATTERN111: $mask = (($row * $_col) % 3 + ($row + $_col) % 2) % 2 === 0; break;
|
|
|
- default :
|
|
|
- throw new QRCodeException('mask: '.$maskPattern);
|
|
|
+
|
|
|
+ $MASK_PATTERN = [
|
|
|
+ QRConst::MASK_PATTERN000 => ($row + $_col) % 2 === 0,
|
|
|
+ QRConst::MASK_PATTERN001 => $row % 2 === 0,
|
|
|
+ QRConst::MASK_PATTERN010 => $_col % 3 === 0,
|
|
|
+ QRConst::MASK_PATTERN011 => ($row + $_col) % 3 === 0,
|
|
|
+ QRConst::MASK_PATTERN100 => (floor($row / 2) + floor($_col / 3)) % 2 === 0,
|
|
|
+ QRConst::MASK_PATTERN101 => ($row * $_col) % 2 + ($row * $_col) % 3 === 0,
|
|
|
+ QRConst::MASK_PATTERN110 => (($row * $_col) % 2 + ($row * $_col) % 3) % 2 === 0,
|
|
|
+ QRConst::MASK_PATTERN111 => (($row * $_col) % 3 + ($row + $_col) % 2) % 2 === 0,
|
|
|
+ ];
|
|
|
+
|
|
|
+ if(!isset($MASK_PATTERN[$pattern])){
|
|
|
+ throw new QRCodeException('mask: '.$pattern);
|
|
|
}
|
|
|
|
|
|
- if($mask){
|
|
|
+ if($MASK_PATTERN[$pattern]){
|
|
|
$dark = !$dark;
|
|
|
}
|
|
|
|
|
|
- $this->modules[$row][$col - $c] = $dark;
|
|
|
+ $this->modules[$row][$col - $c] = (bool)$dark;
|
|
|
$bitIndex--;
|
|
|
|
|
|
if($bitIndex === -1){
|
|
|
@@ -328,198 +502,29 @@ class QRCode{
|
|
|
return $this;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * @return $this
|
|
|
- */
|
|
|
- protected function setupPositionAdjustPattern(){
|
|
|
- $pos = $this->util->PATTERN_POSITION[$this->typeNumber - 1];
|
|
|
-
|
|
|
- foreach($pos as $i => $posI){
|
|
|
- foreach($pos as $j => $posJ){
|
|
|
- if($this->modules[$posI][$posJ] !== null){
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- for($row = -2; $row <= 2; $row++){
|
|
|
- for($col = -2; $col <= 2; $col++){
|
|
|
- $this->modules[$posI + $row][$posJ + $col] =
|
|
|
- (bool)$row === -2 || $row === 2 || $col === -2 || $col === 2 || ($row === 0 && $col === 0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @return $this
|
|
|
- */
|
|
|
- protected function setupTimingPattern(){
|
|
|
-
|
|
|
- for($i = 8; $i < $this->moduleCount - 8; $i++){
|
|
|
- if($this->modules[$i][6] !== null){
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- $this->modules[$i][6] = $this->modules[6][$i] = $i % 2 === 0;
|
|
|
- }
|
|
|
-
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @return int
|
|
|
- */
|
|
|
- protected function getBestMaskPattern(){
|
|
|
- $minLostPoint = 0;
|
|
|
- $pattern = 0;
|
|
|
-
|
|
|
- for($i = 0; $i < 8; $i++){
|
|
|
- $this->makeImpl(true, $i);
|
|
|
- $lostPoint = 0;
|
|
|
-
|
|
|
- // LEVEL1
|
|
|
-
|
|
|
- for($row = 0; $row < $this->moduleCount; $row++){
|
|
|
- for($col = 0; $col < $this->moduleCount; $col++){
|
|
|
- $sameCount = 0;
|
|
|
- $dark = $this->isDark($row, $col);
|
|
|
-
|
|
|
- for($r = -1; $r <= 1; $r++){
|
|
|
- if($row + $r < 0 || $this->moduleCount <= $row + $r){
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- for($c = -1; $c <= 1; $c++){
|
|
|
-
|
|
|
- if($col + $c < 0 || $this->moduleCount <= $col + $c){
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if($r == 0 && $c == 0){
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if($dark === $this->isDark($row + $r, $col + $c)){
|
|
|
- $sameCount++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if($sameCount > 5){
|
|
|
- $lostPoint += (3 + $sameCount - 5);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // LEVEL2
|
|
|
-
|
|
|
- for($row = 0; $row < $this->moduleCount - 1; $row++){
|
|
|
- for($col = 0; $col < $this->moduleCount - 1; $col++){
|
|
|
- $count = 0;
|
|
|
-
|
|
|
- if($this->isDark($row, $col)){
|
|
|
- $count++;
|
|
|
- }
|
|
|
-
|
|
|
- if($this->isDark($row + 1, $col)){
|
|
|
- $count++;
|
|
|
- }
|
|
|
-
|
|
|
- if($this->isDark($row, $col + 1)){
|
|
|
- $count++;
|
|
|
- }
|
|
|
-
|
|
|
- if($this->isDark($row + 1, $col + 1)){
|
|
|
- $count++;
|
|
|
- }
|
|
|
-
|
|
|
- if($count === 0 || $count === 4){
|
|
|
- $lostPoint += 3;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // LEVEL3
|
|
|
-
|
|
|
- for($row = 0; $row < $this->moduleCount; $row++){
|
|
|
- for($col = 0; $col < $this->moduleCount - 6; $col++){
|
|
|
- if($this->isDark($row, $col)
|
|
|
- && !$this->isDark($row, $col + 1)
|
|
|
- && $this->isDark($row, $col + 2)
|
|
|
- && $this->isDark($row, $col + 3)
|
|
|
- && $this->isDark($row, $col + 4)
|
|
|
- && !$this->isDark($row, $col + 5)
|
|
|
- && $this->isDark($row, $col + 6)
|
|
|
- ){
|
|
|
- $lostPoint += 40;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for($col = 0; $col < $this->moduleCount; $col++){
|
|
|
- for($row = 0; $row < $this->moduleCount - 6; $row++){
|
|
|
- if($this->isDark($row, $col)
|
|
|
- && !$this->isDark($row + 1, $col)
|
|
|
- && $this->isDark($row + 2, $col)
|
|
|
- && $this->isDark($row + 3, $col)
|
|
|
- && $this->isDark($row + 4, $col)
|
|
|
- && !$this->isDark($row + 5, $col)
|
|
|
- && $this->isDark($row + 6, $col)
|
|
|
- ){
|
|
|
- $lostPoint += 40;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // LEVEL4
|
|
|
-
|
|
|
- $darkCount = 0;
|
|
|
- for($col = 0; $col < $this->moduleCount; $col++){
|
|
|
- for($row = 0; $row < $this->moduleCount; $row++){
|
|
|
- if($this->isDark($row, $col)){
|
|
|
- $darkCount++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- $ratio = abs(100 * $darkCount / $this->moduleCount / $this->moduleCount - 50) / 5;
|
|
|
- $lostPoint += $ratio * 10;
|
|
|
-
|
|
|
- if($i === 0 || $minLostPoint > $lostPoint){
|
|
|
- $minLostPoint = $lostPoint;
|
|
|
- $pattern = $i;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return $pattern;
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* @param $typeNumber
|
|
|
* @param $errorCorrectLevel
|
|
|
*
|
|
|
* @return array
|
|
|
* @throws \codemasher\QRCode\QRCodeException
|
|
|
- * @todo: slooooow in PHP5
|
|
|
- *
|
|
|
*/
|
|
|
protected function createData($typeNumber, $errorCorrectLevel){
|
|
|
$this->bitBuffer->buffer = [];
|
|
|
$this->bitBuffer->length = 0;
|
|
|
-
|
|
|
$this->rsBlockList = $this->rsBlock->getRSBlocks($typeNumber, $errorCorrectLevel);
|
|
|
+ $rsBlockCount = count($this->rsBlockList);
|
|
|
+
|
|
|
+ $totalDataCount = $totalCodeCount = $offset = $maxDcCount = $maxEcCount = $index = 0;
|
|
|
+ $dcdata = $ecdata = array_fill(0, $rsBlockCount, null);
|
|
|
|
|
|
- $totalDataCount = $totalCodeCount = $offset = $maxDcCount = $maxEcCount = 0;
|
|
|
|
|
|
- /** @var \codemasher\QRCode\Data\QRDataInterface $data */
|
|
|
+ /** @var \codemasher\QRCode\Data\QRDataBase $data */
|
|
|
foreach($this->qrDataList as &$data){
|
|
|
- $len = $data->mode === QRConst::MODE_KANJI ? floor($data->dataLength / 2) : $data->dataLength;
|
|
|
+ $this->bitBuffer
|
|
|
+ ->put($data->mode, 4)
|
|
|
+ ->put($data->mode === QRConst::MODE_KANJI ? floor($data->dataLength / 2) : $data->dataLength, $data->getLengthInBits($typeNumber));
|
|
|
|
|
|
- $this->bitBuffer->put($data->mode, 4);
|
|
|
- $this->bitBuffer->put($len, $data->getLengthInBits($typeNumber));
|
|
|
$data->write($this->bitBuffer);
|
|
|
}
|
|
|
|
|
|
@@ -560,9 +565,6 @@ class QRCode{
|
|
|
$this->bitBuffer->put(self::QR_PAD1, 8);
|
|
|
}
|
|
|
|
|
|
- $rsBlockCount = count($this->rsBlockList);
|
|
|
- $dcdata = $ecdata = array_fill(0, $rsBlockCount, null);
|
|
|
-
|
|
|
foreach($this->rsBlockList as $r => &$_rsData){
|
|
|
$this->rsBlock->totalCount = $_rsData[0];
|
|
|
$this->rsBlock->dataCount = $_rsData[1];
|
|
|
@@ -582,13 +584,11 @@ class QRCode{
|
|
|
|
|
|
$offset += $this->rsBlock->dataCount;
|
|
|
|
|
|
- // PHP5: 0.09s
|
|
|
for($i = 0; $i < $this->rsBlock->totalCount - $this->rsBlock->dataCount; $i++){
|
|
|
$modPoly->setNum([1, $modPoly->gexp($i)]);
|
|
|
$rsPoly->multiply($modPoly->num);
|
|
|
}
|
|
|
|
|
|
- // PHP5: 0.11s
|
|
|
$rsPolyCount = count($rsPoly->num);
|
|
|
$modPoly->setNum($dcdata[$r], $rsPolyCount - 1)->mod($rsPoly->num);
|
|
|
$ecdata[$r] = array_fill(0, $rsPolyCount - 1, null);
|
|
|
@@ -603,7 +603,6 @@ class QRCode{
|
|
|
}
|
|
|
|
|
|
$data = array_fill(0, $totalCodeCount, null);
|
|
|
- $index = 0;
|
|
|
|
|
|
for($i = 0; $i < $maxDcCount; $i++){
|
|
|
for($r = 0; $r < $rsBlockCount; $r++){
|
|
|
@@ -681,7 +680,7 @@ class QRCode{
|
|
|
|
|
|
for($r = 0; $r < $this->moduleCount; $r++){
|
|
|
for($c = 0; $c < $this->moduleCount; $c++){
|
|
|
- if($this->isDark($r, $c)){
|
|
|
+ if($this->modules[$r][$c]){
|
|
|
|
|
|
// update $black to $fgc
|
|
|
imagefilledrectangle($image,
|
|
|
@@ -707,7 +706,7 @@ class QRCode{
|
|
|
$html .= '<tr>';
|
|
|
|
|
|
for($col = 0; $col < $this->moduleCount; $col++){
|
|
|
- $html .= '<td class="'.($this->isDark($row, $col) ? 'dark' : 'light').'"></td>';
|
|
|
+ $html .= '<td class="'.($this->modules[$row][$col] ? 'dark' : 'light').'"></td>';
|
|
|
}
|
|
|
|
|
|
$html .= '</tr>';
|