smiley 10 лет назад
Родитель
Сommit
02b289e366
9 измененных файлов с 317 добавлено и 377 удалено
  1. 0 8
      src/BitBuffer.php
  2. 10 5
      src/Data/AlphaNum.php
  3. 9 4
      src/Data/Byte.php
  4. 9 10
      src/Data/Kanji.php
  5. 12 7
      src/Data/Number.php
  6. 20 48
      src/Data/QRDataBase.php
  7. 2 6
      src/Data/QRDataInterface.php
  8. 252 286
      src/QRCode.php
  9. 3 3
      src/RSBlock.php

+ 0 - 8
src/BitBuffer.php

@@ -26,14 +26,6 @@ class BitBuffer{
 	 */
 	 */
 	public $length = 0;
 	public $length = 0;
 
 
-	/**
-	 *
-	 */
-	public function reset(){
-		$this->buffer = [];
-		$this->length = 0;
-	}
-
 	/**
 	/**
 	 * @return string
 	 * @return string
 	 */
 	 */

+ 10 - 5
src/Data/AlphaNum.php

@@ -1,5 +1,6 @@
 <?php
 <?php
 /**
 /**
+ * Class AlphaNum
  *
  *
  * @filesource   AlphaNum.php
  * @filesource   AlphaNum.php
  * @created      25.11.2015
  * @created      25.11.2015
@@ -12,14 +13,13 @@
 namespace codemasher\QRCode\Data;
 namespace codemasher\QRCode\Data;
 
 
 use codemasher\QRCode\BitBuffer;
 use codemasher\QRCode\BitBuffer;
-use codemasher\QRCode\Data;
 use codemasher\QRCode\Data\QRDataBase;
 use codemasher\QRCode\Data\QRDataBase;
 use codemasher\QRCode\Data\QRDataInterface;
 use codemasher\QRCode\Data\QRDataInterface;
 use codemasher\QRCode\QRCodeException;
 use codemasher\QRCode\QRCodeException;
 use codemasher\QRCode\QRConst;
 use codemasher\QRCode\QRConst;
 
 
 /**
 /**
- * Class AlphaNum
+ *
  */
  */
 class AlphaNum extends QRDataBase implements QRDataInterface{
 class AlphaNum extends QRDataBase implements QRDataInterface{
 
 
@@ -28,21 +28,26 @@ class AlphaNum extends QRDataBase implements QRDataInterface{
 	 */
 	 */
 	public $mode = QRConst::MODE_ALPHANUM;
 	public $mode = QRConst::MODE_ALPHANUM;
 
 
+	/**
+	 * @var array
+	 */
+	protected $lengthBits = [9, 11, 13];
+
 	/**
 	/**
 	 * @param $buffer
 	 * @param $buffer
 	 */
 	 */
 	public function write(BitBuffer &$buffer){
 	public function write(BitBuffer &$buffer){
 
 
 		$i = 0;
 		$i = 0;
-		$len = strlen($this->data);
-		while($i + 1 < $len){
+		while($i + 1 < $this->dataLength){
 			$buffer->put($this->getCode(ord($this->data[$i])) * 45 + $this->getCode(ord($this->data[$i + 1])), 11);
 			$buffer->put($this->getCode(ord($this->data[$i])) * 45 + $this->getCode(ord($this->data[$i + 1])), 11);
 			$i += 2;
 			$i += 2;
 		}
 		}
 
 
-		if($i < $len){
+		if($i < $this->dataLength){
 			$buffer->put($this->getCode(ord($this->data[$i])), 6);
 			$buffer->put($this->getCode(ord($this->data[$i])), 6);
 		}
 		}
+
 	}
 	}
 
 
 	/**
 	/**

+ 9 - 4
src/Data/Byte.php

@@ -1,5 +1,6 @@
 <?php
 <?php
 /**
 /**
+ * Class Byte
  *
  *
  * @filesource   Byte.php
  * @filesource   Byte.php
  * @created      25.11.2015
  * @created      25.11.2015
@@ -18,7 +19,7 @@ use codemasher\QRCode\Data\QRDataInterface;
 
 
 
 
 /**
 /**
- * Class Byte
+ *
  */
  */
 class Byte extends QRDataBase implements QRDataInterface{
 class Byte extends QRDataBase implements QRDataInterface{
 
 
@@ -27,14 +28,18 @@ class Byte extends QRDataBase implements QRDataInterface{
 	 */
 	 */
 	public $mode = QRConst::MODE_BYTE;
 	public $mode = QRConst::MODE_BYTE;
 
 
+	/**
+	 * @var array
+	 */
+	protected $lengthBits = [8, 16, 16];
+
 	/**
 	/**
 	 * @param $buffer
 	 * @param $buffer
 	 */
 	 */
 	public function write(BitBuffer &$buffer){
 	public function write(BitBuffer &$buffer){
-		$len = strlen($this->data);
-		for($i = 0; $i < $len; $i++){
+		for($i = 0; $i < $this->dataLength; $i++){
 			$buffer->put(ord($this->data[$i]), 8);
 			$buffer->put(ord($this->data[$i]), 8);
 		}
 		}
 	}
 	}
 
 
-}
+}

+ 9 - 10
src/Data/Kanji.php

@@ -1,5 +1,6 @@
 <?php
 <?php
 /**
 /**
+ * Class Kanji
  *
  *
  * @filesource   Kanji.php
  * @filesource   Kanji.php
  * @created      25.11.2015
  * @created      25.11.2015
@@ -18,7 +19,7 @@ use codemasher\QRCode\QRCodeException;
 use codemasher\QRCode\QRConst;
 use codemasher\QRCode\QRConst;
 
 
 /**
 /**
- * Class Kanji
+ *
  */
  */
 class Kanji extends QRDataBase implements QRDataInterface{
 class Kanji extends QRDataBase implements QRDataInterface{
 
 
@@ -27,6 +28,11 @@ class Kanji extends QRDataBase implements QRDataInterface{
 	 */
 	 */
 	public $mode = QRConst::MODE_KANJI;
 	public $mode = QRConst::MODE_KANJI;
 
 
+	/**
+	 * @var array
+	 */
+	protected $lengthBits = [8, 10, 12];
+
 	/**
 	/**
 	 * @param $buffer
 	 * @param $buffer
 	 *
 	 *
@@ -35,8 +41,7 @@ class Kanji extends QRDataBase implements QRDataInterface{
 	public function write(BitBuffer &$buffer){
 	public function write(BitBuffer &$buffer){
 
 
 		$i = 0;
 		$i = 0;
-		$len = strlen($this->data);
-		while($i + 1 < $len){
+		while($i + 1 < $this->dataLength){
 			$c = ((0xff&ord($this->data[$i])) << 8)|(0xff&ord($this->data[$i + 1]));
 			$c = ((0xff&ord($this->data[$i])) << 8)|(0xff&ord($this->data[$i + 1]));
 
 
 			if(0x8140 <= $c && $c <= 0x9FFC){
 			if(0x8140 <= $c && $c <= 0x9FFC){
@@ -54,16 +59,10 @@ class Kanji extends QRDataBase implements QRDataInterface{
 			$i += 2;
 			$i += 2;
 		}
 		}
 
 
-		if($i < $len){
+		if($i < $this->dataLength){
 			throw new QRCodeException('illegal char at '.($i + 1));
 			throw new QRCodeException('illegal char at '.($i + 1));
 		}
 		}
-	}
 
 
-	/**
-	 * @return float
-	 */
-	public function getLength(){
-		return floor(strlen($this->data) / 2);
 	}
 	}
 
 
 }
 }

+ 12 - 7
src/Data/Number.php

@@ -1,5 +1,6 @@
 <?php
 <?php
 /**
 /**
+ * Class Number
  *
  *
  * @filesource   Number.php
  * @filesource   Number.php
  * @created      26.11.2015
  * @created      26.11.2015
@@ -18,7 +19,7 @@ use codemasher\QRCode\QRCodeException;
 use codemasher\QRCode\QRConst;
 use codemasher\QRCode\QRConst;
 
 
 /**
 /**
- * Class Number
+ *
  */
  */
 class Number extends QRDataBase implements QRDataInterface{
 class Number extends QRDataBase implements QRDataInterface{
 
 
@@ -27,6 +28,11 @@ class Number extends QRDataBase implements QRDataInterface{
 	 */
 	 */
 	public $mode = QRConst::MODE_NUMBER;
 	public $mode = QRConst::MODE_NUMBER;
 
 
+	/**
+	 * @var array
+	 */
+	protected $lengthBits = [10, 12, 14];
+
 	/**
 	/**
 	 * @param $buffer
 	 * @param $buffer
 	 *
 	 *
@@ -35,20 +41,19 @@ class Number extends QRDataBase implements QRDataInterface{
 	public function write(BitBuffer &$buffer){
 	public function write(BitBuffer &$buffer){
 
 
 		$i = 0;
 		$i = 0;
-		$len = strlen($this->data);
-		while($i + 2 < $len){
+		while($i + 2 < $this->dataLength){
 			$num = $this->parseInt(substr($this->data, $i, 3));
 			$num = $this->parseInt(substr($this->data, $i, 3));
 			$buffer->put($num, 10);
 			$buffer->put($num, 10);
 			$i += 3;
 			$i += 3;
 		}
 		}
 
 
-		if($i < $len){
+		if($i < $this->dataLength){
 
 
-			if($len - $i === 1){
+			if($this->dataLength - $i === 1){
 				$num = $this->parseInt(substr($this->data, $i, $i + 1));
 				$num = $this->parseInt(substr($this->data, $i, $i + 1));
 				$buffer->put($num, 4);
 				$buffer->put($num, 4);
 			}
 			}
-			else if($len - $i === 2){
+			else if($this->dataLength - $i === 2){
 				$num = $this->parseInt(substr($this->data, $i, $i + 2));
 				$num = $this->parseInt(substr($this->data, $i, $i + 2));
 				$buffer->put($num, 7);
 				$buffer->put($num, 7);
 			}
 			}
@@ -65,8 +70,8 @@ class Number extends QRDataBase implements QRDataInterface{
 	 * @throws \codemasher\QRCode\QRCodeException
 	 * @throws \codemasher\QRCode\QRCodeException
 	 */
 	 */
 	protected function parseInt($string){
 	protected function parseInt($string){
-		$num = 0;
 
 
+		$num = 0;
 		$len = strlen($string);
 		$len = strlen($string);
 		for($i = 0; $i < $len; $i++){
 		for($i = 0; $i < $len; $i++){
 			$c = ord($string[$i]);
 			$c = ord($string[$i]);

+ 20 - 48
src/Data/QRDataBase.php

@@ -1,5 +1,6 @@
 <?php
 <?php
 /**
 /**
+ * Class QRDataBase
  *
  *
  * @filesource   QRDataBase.php
  * @filesource   QRDataBase.php
  * @created      25.11.2015
  * @created      25.11.2015
@@ -17,7 +18,7 @@ use codemasher\QRCode\QRCodeException;
 use codemasher\QRCode\Util;
 use codemasher\QRCode\Util;
 
 
 /**
 /**
- * Class QRDataBase
+ *
  */
  */
 class QRDataBase{
 class QRDataBase{
 
 
@@ -27,10 +28,20 @@ class QRDataBase{
 	public $mode;
 	public $mode;
 
 
 	/**
 	/**
-	 * @var
+	 * @var string
 	 */
 	 */
 	public $data;
 	public $data;
 
 
+	/**
+	 * @var int
+	 */
+	public $dataLength;
+
+	/**
+	 * @var array
+	 */
+	protected $lengthBits = [0, 0, 0];
+
 	/**
 	/**
 	 * @var \codemasher\QRCode\Util
 	 * @var \codemasher\QRCode\Util
 	 */
 	 */
@@ -43,16 +54,10 @@ class QRDataBase{
 	 */
 	 */
 	public function __construct($data){
 	public function __construct($data){
 		$this->data = $data;
 		$this->data = $data;
+		$this->dataLength = strlen($data);
 		$this->util = new Util;
 		$this->util = new Util;
 	}
 	}
 
 
-	/**
-	 * @throws \codemasher\QRCode\QRCodeException
-	 */
-	public function getLength(){
-		return strlen($this->data);
-	}
-
 	/**
 	/**
 	 * @param $type
 	 * @param $type
 	 *
 	 *
@@ -60,48 +65,15 @@ class QRDataBase{
 	 * @throws \codemasher\QRCode\QRCodeException
 	 * @throws \codemasher\QRCode\QRCodeException
 	 */
 	 */
 	public function getLengthInBits($type){
 	public function getLengthInBits($type){
-		if(1 <= $type && $type < 10){
-
-			// 1 - 9
-			switch($this->mode){
-				case QRConst::MODE_NUMBER  : return 10;
-				case QRConst::MODE_ALPHANUM: return 9;
-				case QRConst::MODE_BYTE    : return 8;
-				case QRConst::MODE_KANJI   : return 8;
-				default :
-					throw new QRCodeException('mode: '.$this->mode);
-			}
 
 
+		switch(true){
+			case 1 <= $type && $type < 10: return $this->lengthBits[0]; break; // 1 - 9
+			case $type < 27: return  $this->lengthBits[1]; break; // 10 - 26
+			case $type < 41: return  $this->lengthBits[2]; break; // 27 - 40
+			default:
+				throw new QRCodeException('mode: '.$this->mode);
 		}
 		}
-		else if($type < 27){
-
-			// 10 - 26
-			switch($this->mode){
-				case QRConst::MODE_NUMBER  : return 12;
-				case QRConst::MODE_ALPHANUM: return 11;
-				case QRConst::MODE_BYTE    : return 16;
-				case QRConst::MODE_KANJI   : return 10;
-				default :
-					throw new QRCodeException('mode: '.$this->mode);
-			}
 
 
-		}
-		else if($type < 41){
-
-			// 27 - 40
-			switch($this->mode){
-				case QRConst::MODE_NUMBER  : return 14;
-				case QRConst::MODE_ALPHANUM: return 13;
-				case QRConst::MODE_BYTE    : return 16;
-				case QRConst::MODE_KANJI   : return 12;
-				default :
-					throw new QRCodeException('mode: '.$this->mode);
-			}
-
-		}
-		else{
-			throw new QRCodeException('mode: '.$this->mode);
-		}
 	}
 	}
 
 
 }
 }

+ 2 - 6
src/Data/QRDataInterface.php

@@ -1,5 +1,6 @@
 <?php
 <?php
 /**
 /**
+ * Interface QRDataInterface
  *
  *
  * @filesource   QRDataInterface.php
  * @filesource   QRDataInterface.php
  * @created      01.12.2015
  * @created      01.12.2015
@@ -13,7 +14,7 @@ namespace codemasher\QRCode\Data;
 use codemasher\QRCode\BitBuffer;
 use codemasher\QRCode\BitBuffer;
 
 
 /**
 /**
- * Interface QRDataInterface
+ *
  */
  */
 interface QRDataInterface{
 interface QRDataInterface{
 
 
@@ -22,11 +23,6 @@ interface QRDataInterface{
 	 */
 	 */
 	public function write(BitBuffer &$buffer);
 	public function write(BitBuffer &$buffer);
 
 
-	/**
-	 * @return int
-	 */
-	public function getLength();
-
 	/**
 	/**
 	 * @param $type
 	 * @param $type
 	 *
 	 *

+ 252 - 286
src/QRCode.php

@@ -106,10 +106,10 @@ class QRCode{
 		}
 		}
 
 
 		switch($mode){
 		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;
+			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:
 			default:
 				throw new QRCodeException('mode: '.$mode);
 				throw new QRCodeException('mode: '.$mode);
 		}
 		}
@@ -142,131 +142,31 @@ class QRCode{
 	}
 	}
 
 
 	/**
 	/**
-	 * @return int
+	 * @param $data
+	 * @param $errorCorrectLevel
+	 *
+	 * @return \codemasher\QRCode\QRCode
+	 * @throws \codemasher\QRCode\QRCodeException
 	 */
 	 */
-	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++;
-					}
-				}
-			}
+	public function getMinimumQRCode($data, $errorCorrectLevel = QRConst::ERROR_CORRECT_LEVEL_H){
+		$mode = $this->util->getMode($data);
+		$this->addData($data, $mode);
+		$this->errorCorrectLevel = $errorCorrectLevel;
 
 
-			$ratio = abs(100 * $darkCount / $this->moduleCount / $this->moduleCount - 50) / 5;
-			$lostPoint += $ratio * 10;
+		/** @var \codemasher\QRCode\Data\QRDataBase $qrData */
+		$qrData = $this->qrDataList[0];
+		$length = $qrData->mode === QRConst::MODE_KANJI ? floor($qrData->dataLength / 2) : $qrData->dataLength;
 
 
-			if($i === 0 || $minLostPoint > $lostPoint){
-				$minLostPoint = $lostPoint;
-				$pattern = $i;
+		for($typeNumber = 1; $typeNumber <= 10; $typeNumber++){
+			if($length <= $this->util->getMaxLength($typeNumber, $mode, $this->errorCorrectLevel)){
+				$this->typeNumber = $typeNumber;
+				break;
 			}
 			}
 		}
 		}
 
 
-		return $pattern;
+		$this->makeImpl(false, $this->getBestMaskPattern());
+
+		return $this;
 	}
 	}
 
 
 	/**
 	/**
@@ -279,46 +179,16 @@ class QRCode{
 		$this->moduleCount = $this->typeNumber * 4 + 17;
 		$this->moduleCount = $this->typeNumber * 4 + 17;
 		$this->modules = [];
 		$this->modules = [];
 
 
-		$nullArray = [];
-		for($i = 0; $i < $this->moduleCount; $i++){
-			$nullArray[] = null;
-		}
-
+		$nullArray = array_fill(0, $this->moduleCount, null);
 		for($i = 0; $i < $this->moduleCount; $i++){
 		for($i = 0; $i < $this->moduleCount; $i++){
 			$this->modules[] = $nullArray;
 			$this->modules[] = $nullArray;
 		}
 		}
 
 
 		$this->setupPositionProbePattern(0, 0)
 		$this->setupPositionProbePattern(0, 0)
 		     ->setupPositionProbePattern($this->moduleCount - 7, 0)
 		     ->setupPositionProbePattern($this->moduleCount - 7, 0)
-		     ->setupPositionProbePattern(0, $this->moduleCount - 7);
-
-
-		$pos = $this->util->PATTERN_POSITION[$this->typeNumber - 1];
-		$posCount = count($pos);
-
-		for($i = 0; $i < $posCount; $i++){
-			for($j = 0; $j < $posCount; $j++){
-				if($this->modules[$pos[$i]][$pos[$j]] !== null){
-					continue;
-				}
-
-				for($r = -2; $r <= 2; $r++){
-					for($c = -2; $c <= 2; $c++){
-						$this->modules[$pos[$i] + $r][$pos[$j] + $c] =
-								$r === -2 || $r === 2 || $c === -2 || $c === 2 || ($r === 0 && $c === 0);
-					}
-				}
-
-			}
-		}
-
-		for($r = 8; $r < $this->moduleCount - 8; $r++){
-			if($this->modules[$r][6] !== null){
-				continue;
-			}
-
-			$this->modules[$r][6] = $this->modules[6][$r] = $r % 2 === 0;
-		}
+		     ->setupPositionProbePattern(0, $this->moduleCount - 7)
+		     ->setupPositionAdjustPattern()
+		     ->setupTimingPattern();
 
 
 		$data = ($this->errorCorrectLevel << 3) | $maskPattern;
 		$data = ($this->errorCorrectLevel << 3) | $maskPattern;
 		$bits = $this->util->getBCHTypeInfo($data);
 		$bits = $this->util->getBCHTypeInfo($data);
@@ -326,24 +196,18 @@ class QRCode{
 		for($i = 0; $i < 15; $i++){
 		for($i = 0; $i < 15; $i++){
 			$mod = !$test && (($bits >> $i) & 1) === 1;
 			$mod = !$test && (($bits >> $i) & 1) === 1;
 
 
-			if($i < 6){
-				$this->modules[$i][8] = $mod;
-			}
-			else if($i < 8){
-				$this->modules[$i + 1][8] = $mod;
-			}
-			else{
-				$this->modules[$this->moduleCount - 15 + $i][8] = $mod;
+			switch(true){
+				case $i < 6: $this->modules[$i][8] = $mod; break;
+				case $i < 8: $this->modules[$i + 1][8] = $mod; break;
+				default:
+					$this->modules[$this->moduleCount - 15 + $i][8] = $mod;
 			}
 			}
 
 
-			if($i < 8){
-				$this->modules[8][$this->moduleCount - $i - 1] = $mod;
-			}
-			else if($i < 9){
-				$this->modules[8][15 - $i - 1 + 1] = $mod;
-			}
-			else{
-				$this->modules[8][15 - $i - 1] = $mod;
+			switch(true){
+				case $i < 8: $this->modules[8][$this->moduleCount - $i - 1] = $mod; break;
+				case $i < 9: $this->modules[8][15 - $i - 1 + 1] = $mod; break;
+				default:
+					$this->modules[8][15 - $i - 1] = $mod;
 			}
 			}
 
 
 		}
 		}
@@ -356,14 +220,12 @@ class QRCode{
 			for($i = 0; $i < 18; $i++){
 			for($i = 0; $i < 18; $i++){
 				$a = (int)floor($i / 3);
 				$a = (int)floor($i / 3);
 				$b = $i % 3 + $this->moduleCount - 8 - 3;
 				$b = $i % 3 + $this->moduleCount - 8 - 3;
-				$mod = !$test && (($bits >> $i) & 1) === 1;
 
 
-				$this->modules[$a][$b] = $this->modules[$b][$a] = $mod;
+				$this->modules[$a][$b] = $this->modules[$b][$a] = !$test && (($bits >> $i) & 1) === 1;
 			}
 			}
 		}
 		}
 
 
 		$this->data = $this->createData($this->typeNumber, $this->errorCorrectLevel);
 		$this->data = $this->createData($this->typeNumber, $this->errorCorrectLevel);
-
 		$this->mapData($maskPattern);
 		$this->mapData($maskPattern);
 
 
 		return $this;
 		return $this;
@@ -447,9 +309,10 @@ class QRCode{
 	 * @return $this
 	 * @return $this
 	 */
 	 */
 	protected function setupPositionProbePattern($row, $col){
 	protected function setupPositionProbePattern($row, $col){
+		$range = range(-1, 7);
 
 
-		for($r = -1; $r <= 7; $r++){
-			for($c = -1; $c <= 7; $c++){
+		foreach($range as $r){
+			foreach($range as $c){
 
 
 				if($row + $r <= -1 || $this->moduleCount <= $row + $r || $col + $c <= -1 || $this->moduleCount <= $col + $c){
 				if($row + $r <= -1 || $this->moduleCount <= $row + $r || $col + $c <= -1 || $this->moduleCount <= $col + $c){
 					continue;
 					continue;
@@ -457,14 +320,183 @@ class QRCode{
 
 
 				$this->modules[$row + $r][$col + $c] =
 				$this->modules[$row + $r][$col + $c] =
 					(0 <= $r && $r <= 6 && ($c === 0 || $c === 6))
 					(0 <= $r && $r <= 6 && ($c === 0 || $c === 6))
-						|| (0 <= $c && $c <= 6 && ($r == 0 || $r === 6))
-						|| (2 <= $r && $r <= 4 && 2 <= $c && $c <= 4);
+					|| (0 <= $c && $c <= 6 && ($r == 0 || $r === 6))
+					|| (2 <= $r && $r <= 4 && 2 <= $c && $c <= 4);
+			}
+		}
+
+		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;
 	}
 	}
 
 
+	/**
+	 * @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 $typeNumber
 	 * @param $errorCorrectLevel
 	 * @param $errorCorrectLevel
@@ -475,25 +507,25 @@ class QRCode{
 	 *
 	 *
 	 */
 	 */
 	protected function createData($typeNumber, $errorCorrectLevel){
 	protected function createData($typeNumber, $errorCorrectLevel){
-		$this->bitBuffer->reset();
+		$this->bitBuffer->buffer = [];
+		$this->bitBuffer->length = 0;
+
+		$this->rsBlockList = $this->rsBlock->getRSBlocks($typeNumber, $errorCorrectLevel);
 
 
-		$count = count($this->qrDataList);
-		for($i = 0; $i < $count; $i++){
-			/** @var \codemasher\QRCode\Data\QRDataInterface $data */
-			$data = $this->qrDataList[$i];
+		$totalDataCount = $totalCodeCount = $offset = $maxDcCount = $maxEcCount = 0;
+
+		/** @var \codemasher\QRCode\Data\QRDataInterface $data */
+		foreach($this->qrDataList as &$data){
+			$len = $data->mode === QRConst::MODE_KANJI ? floor($data->dataLength / 2) : $data->dataLength;
 
 
 			$this->bitBuffer->put($data->mode, 4);
 			$this->bitBuffer->put($data->mode, 4);
-			$this->bitBuffer->put($data->getLength(), $data->getLengthInBits($typeNumber));
+			$this->bitBuffer->put($len, $data->getLengthInBits($typeNumber));
 			$data->write($this->bitBuffer);
 			$data->write($this->bitBuffer);
 		}
 		}
 
 
-		$this->rsBlockList = $this->rsBlock->getRSBlocks($typeNumber, $errorCorrectLevel);
-		$totalDataCount = 0;
-
-		$count = count($this->rsBlockList);
-		for($i = 0; $i < $count; $i++){
-			$this->rsBlock->totalCount = $this->rsBlockList[$i][0];
-			$this->rsBlock->dataCount = $this->rsBlockList[$i][1];
+		foreach($this->rsBlockList as &$data){
+			$this->rsBlock->totalCount = $data[0];
+			$this->rsBlock->dataCount = $data[1];
 
 
 			$totalDataCount += $this->rsBlock->dataCount;
 			$totalDataCount += $this->rsBlock->dataCount;
 		}
 		}
@@ -508,7 +540,7 @@ class QRCode{
 		}
 		}
 
 
 		// padding
 		// padding
-		while($this->bitBuffer->length % 8 != 0){
+		while($this->bitBuffer->length % 8 !== 0){
 			$this->bitBuffer->putBit(false);
 			$this->bitBuffer->putBit(false);
 		}
 		}
 
 
@@ -518,6 +550,7 @@ class QRCode{
 			if($this->bitBuffer->length >= $totalDataCount * 8){
 			if($this->bitBuffer->length >= $totalDataCount * 8){
 				break;
 				break;
 			}
 			}
+
 			$this->bitBuffer->put(self::QR_PAD0, 8);
 			$this->bitBuffer->put(self::QR_PAD0, 8);
 
 
 			if($this->bitBuffer->length >= $totalDataCount * 8){
 			if($this->bitBuffer->length >= $totalDataCount * 8){
@@ -527,88 +560,51 @@ class QRCode{
 			$this->bitBuffer->put(self::QR_PAD1, 8);
 			$this->bitBuffer->put(self::QR_PAD1, 8);
 		}
 		}
 
 
-
-		$offset = $maxDcCount = $maxEcCount = 0;
 		$rsBlockCount = count($this->rsBlockList);
 		$rsBlockCount = count($this->rsBlockList);
+		$dcdata = $ecdata = array_fill(0, $rsBlockCount, null);
 
 
-		$nullArray = [];
-		for($i = 0; $i < $rsBlockCount; $i++){
-			$nullArray[] = null;
-		}
+		foreach($this->rsBlockList as $r => &$_rsData){
+			$this->rsBlock->totalCount = $_rsData[0];
+			$this->rsBlock->dataCount = $_rsData[1];
 
 
-		$dcdata = $ecdata = $nullArray;
-		$totalCodeCount = 0;
+			$maxDcCount = max($maxDcCount, $this->rsBlock->dataCount);
+			$maxEcCount = max($maxEcCount, $this->rsBlock->totalCount - $this->rsBlock->dataCount);
 
 
-		for($r = 0; $r < $rsBlockCount; $r++){
-			$this->rsBlock->totalCount = $this->rsBlockList[$r][0];
-			$this->rsBlock->dataCount = $this->rsBlockList[$r][1];
+			$dcdata[$r] = array_fill(0, $this->rsBlock->dataCount, null);
 
 
+			$rsPoly = new Polynomial;
+			$modPoly = new Polynomial;
 
 
-			$dcCount = $this->rsBlock->dataCount;
-			$ecCount = $this->rsBlock->totalCount - $dcCount;
-
-			$maxDcCount = max($maxDcCount, $dcCount);
-			$maxEcCount = max($maxEcCount, $ecCount);
-
-			$_nullArray = [];
-			for($i = 0; $i < $dcCount; $i++){
-				$_nullArray[] = null;
-			}
-
-			$dcdata[$r] = $_nullArray;
-			$dcdataCount = count($dcdata[$r]);
-			for($i = 0; $i < $dcdataCount; $i++){
+			foreach($dcdata[$r] as $i => &$_dcdata){
 				$bdata = $this->bitBuffer->buffer;
 				$bdata = $this->bitBuffer->buffer;
-				$dcdata[$r][$i] = 0xff & $bdata[$i + $offset];
+				$_dcdata = 0xff & $bdata[$i + $offset];
 			}
 			}
-			$offset += $dcCount;
-
 
 
-			$rsPoly = new Polynomial;
-			$modPoly = new Polynomial;
+			$offset += $this->rsBlock->dataCount;
 
 
-$starttime = microtime(true);
-			// 0.09s
-			for($i = 0; $i < $ecCount; $i++){
+			// PHP5: 0.09s
+			for($i = 0; $i < $this->rsBlock->totalCount - $this->rsBlock->dataCount; $i++){
 				$modPoly->setNum([1, $modPoly->gexp($i)]);
 				$modPoly->setNum([1, $modPoly->gexp($i)]);
 				$rsPoly->multiply($modPoly->num);
 				$rsPoly->multiply($modPoly->num);
 			}
 			}
 
 
+			// PHP5: 0.11s
 			$rsPolyCount = count($rsPoly->num);
 			$rsPolyCount = count($rsPoly->num);
-
-			// 0.11s
 			$modPoly->setNum($dcdata[$r], $rsPolyCount - 1)->mod($rsPoly->num);
 			$modPoly->setNum($dcdata[$r], $rsPolyCount - 1)->mod($rsPoly->num);
+			$ecdata[$r] = array_fill(0, $rsPolyCount - 1, null);
+			$add = count($modPoly->num) - count($ecdata[$r]);
 
 
-echo 'QRCode::createData '.round((microtime(true)-$starttime), 5).PHP_EOL;
-
-			$modPolyCount = count($modPoly->num);
-
-			$_nullArray = [];
-			for($i = 0; $i < $rsPolyCount - 1; $i++){
-				$_nullArray[] = null;
+			foreach($ecdata[$r] as $i => &$_ecdata){
+				$modIndex = $i + $add;
+				$_ecdata = $modIndex >= 0 ? $modPoly->num[$modIndex] : 0;
 			}
 			}
 
 
-			$ecdata[$r] = $_nullArray;
-			$ecdataCount = count($ecdata[$r]);
-
-			for($i = 0; $i < $ecdataCount; $i++){
-				$modIndex = $i + $modPolyCount - $ecdataCount;
-				$ecdata[$r][$i] = ($modIndex >= 0) ? $modPoly->num[$modIndex] : 0;
-			}
-
-			$this->rsBlock->totalCount = $this->rsBlockList[$r][0];
-			$this->rsBlock->dataCount = $this->rsBlockList[$r][1];
-
 			$totalCodeCount += $this->rsBlock->totalCount;
 			$totalCodeCount += $this->rsBlock->totalCount;
 		}
 		}
 
 
-		$nullArray = [];
-		for($i = 0; $i < $totalCodeCount; $i++){
-			$nullArray[] = null;
-		}
-
-		$data = $nullArray;
+		$data = array_fill(0, $totalCodeCount, null);
 		$index = 0;
 		$index = 0;
+
 		for($i = 0; $i < $maxDcCount; $i++){
 		for($i = 0; $i < $maxDcCount; $i++){
 			for($r = 0; $r < $rsBlockCount; $r++){
 			for($r = 0; $r < $rsBlockCount; $r++){
 				if($i < count($dcdata[$r])){
 				if($i < count($dcdata[$r])){
@@ -628,35 +624,6 @@ echo 'QRCode::createData '.round((microtime(true)-$starttime), 5).PHP_EOL;
 		return $data;
 		return $data;
 	}
 	}
 
 
-	/**
-	 * @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;
-
-		/** @var \codemasher\QRCode\Data\QRDataBase $qrData */
-		$qrData = $this->qrDataList[0];
-		$length = $qrData->getLength();
-
-		for($typeNumber = 1; $typeNumber <= 10; $typeNumber++){
-			if($length <= $this->util->getMaxLength($typeNumber, $mode, $this->errorCorrectLevel)){
-				$this->typeNumber = $typeNumber;
-				break;
-			}
-		}
-
-		$this->makeImpl(false, $this->getBestMaskPattern());
-
-		return $this;
-	}
-
 	/**
 	/**
 	 * added $fg (foreground), $bg (background), and $bgtrans (use transparent bg) parameters
 	 * added $fg (foreground), $bg (background), and $bgtrans (use transparent bg) parameters
 	 * also added some simple error checking on parameters
 	 * also added some simple error checking on parameters
@@ -735,13 +702,12 @@ echo 'QRCode::createData '.round((microtime(true)-$starttime), 5).PHP_EOL;
 	 */
 	 */
 	public function printHTML(){
 	public function printHTML(){
 		$html = '<table class="qrcode">';
 		$html = '<table class="qrcode">';
-		$count = $this->moduleCount;
 
 
-		for($r = 0; $r < $count; $r++){
+		for($row = 0; $row < $this->moduleCount; $row++){
 			$html .= '<tr>';
 			$html .= '<tr>';
 
 
-			for($c = 0; $c < $count; $c++){
-				$html .= '<td class="'.($this->isDark($r, $c) ? 'dark' : 'light').'"></td>';
+			for($col = 0; $col < $this->moduleCount; $col++){
+				$html .= '<td class="'.($this->isDark($row, $col) ? 'dark' : 'light').'"></td>';
 			}
 			}
 
 
 			$html .= '</tr>';
 			$html .= '</tr>';

+ 3 - 3
src/RSBlock.php

@@ -32,7 +32,7 @@ class RSBlock{
 	/**
 	/**
 	 * @var array
 	 * @var array
 	 */
 	 */
-	protected $QR_RS_BLOCK_TABLE = [
+	protected $BLOCK_TABLE = [
 
 
 		// L
 		// L
 		// M
 		// M
@@ -116,10 +116,10 @@ class RSBlock{
 			case QRConst::ERROR_CORRECT_LEVEL_Q: $rsBlock = 2; break;
 			case QRConst::ERROR_CORRECT_LEVEL_Q: $rsBlock = 2; break;
 			case QRConst::ERROR_CORRECT_LEVEL_H: $rsBlock = 3; break;
 			case QRConst::ERROR_CORRECT_LEVEL_H: $rsBlock = 3; break;
 			default:
 			default:
-				throw new QRCodeException('tn:'.$typeNumber.'/ecl:'.$errorCorrectLevel);
+				throw new QRCodeException('$typeNumber:'.$typeNumber.'/$errorCorrectLevel:'.$errorCorrectLevel);
 		}
 		}
 
 
-		$rsBlock = $this->QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + $rsBlock];
+		$rsBlock = $this->BLOCK_TABLE[($typeNumber - 1) * 4 + $rsBlock];
 
 
 		$list = [];
 		$list = [];
 		$length = count($rsBlock) / 3;
 		$length = count($rsBlock) / 3;