smiley 10 лет назад
Родитель
Сommit
b3ee487ef3
2 измененных файлов с 257 добавлено и 260 удалено
  1. 157 260
      src/QRCode.php
  2. 100 0
      src/Util.php

+ 157 - 260
src/QRCode.php

@@ -149,7 +149,7 @@ class QRCode{
 				: $this->qrDataInterface->dataLength;
 
 			for($type = 1; $type <= 10; $type++){
-				if($length <= $this->getMaxLength($type, $mode, $this->errorCorrectLevel)){
+				if($length <= Util::getMaxLength($type, $mode, $this->errorCorrectLevel)){
 					$this->typeNumber = $type;
 
 					return $this;
@@ -158,7 +158,6 @@ class QRCode{
 
 		}
 
-
 		return $this;
 	}
 
@@ -294,73 +293,18 @@ class QRCode{
 	}
 
 	/**
-	 * @param int $typeNumber
-	 * @param int $mode
-	 * @param int $ecLevel
-	 *
-	 * @return int
-	 * @throws \chillerlan\QRCode\QRCodeException
-	 */
-	protected static function getMaxLength($typeNumber, $mode, $ecLevel){
-		$RSBLOCK = QRConst::RSBLOCK;
-		$MAX_LENGTH = QRConst::MAX_LENGTH;
-		$MODE = QRConst::MODE;
-
-		if(!isset($RSBLOCK[$ecLevel])){
-			throw new QRCodeException('$_err: '.$ecLevel);
-		}
-
-		if(!isset($MODE[$mode])){
-			throw new QRCodeException('$_mode: '.$mode);
-		}
-
-		return $MAX_LENGTH[$typeNumber - 1][$RSBLOCK[$ecLevel]][$MODE[$mode]];
-	}
-
-	/**
-	 * @param int $data
-	 *
-	 * @return int
-	 */
-	protected static function getBCHTypeInfo($data){
-		$d = $data << 10;
-
-		while(self::getBCHDigit($d) - self::getBCHDigit(QRConst::G15) >= 0){
-			$d ^= (QRConst::G15 << (self::getBCHDigit($d) - self::getBCHDigit(QRConst::G15)));
-		}
-
-		return (($data << 10)|$d)^QRConst::G15_MASK;
-	}
-
-	/**
-	 * @param int $data
-	 *
-	 * @return int
+	 * @param bool $test
 	 */
-	protected static function getBCHTypeNumber($data){
-		$d = $data << 12;
-
-		while(self::getBCHDigit($d) - self::getBCHDigit(QRConst::G18) >= 0){
-			$d ^= (QRConst::G18 << (self::getBCHDigit($d) - self::getBCHDigit(QRConst::G18)));
-		}
-
-		return ($data << 12)|$d;
-	}
+	protected function setTypeNumber($test){
+		$bits = Util::getBCHTypeNumber($this->typeNumber);
 
-	/**
-	 * @param int $data
-	 *
-	 * @return int
-	 */
-	protected static function getBCHDigit($data){
-		$digit = 0;
+		for($i = 0; $i < 18; $i++){
+			$a = (int)floor($i / 3);
+			$b = $i % 3 + $this->pixelCount - 8 - 3;
 
-		while($data !== 0){
-			$digit++;
-			$data >>= 1;
+			$this->matrix[$a][$b] = $this->matrix[$b][$a] = !$test && (($bits >> $i) & 1) === 1;
 		}
 
-		return $digit;
 	}
 
 	/**
@@ -369,7 +313,7 @@ class QRCode{
 	 */
 	protected function setTypeInfo($test, $pattern){
 		$this->setPattern();
-		$bits = self::getBCHTypeInfo(($this->errorCorrectLevel << 3) | $pattern);
+		$bits = Util::getBCHTypeInfo(($this->errorCorrectLevel << 3) | $pattern);
 
 		for($i = 0; $i < 15; $i++){
 			$mod = !$test && (($bits >> $i) & 1) === 1;
@@ -396,99 +340,125 @@ class QRCode{
 	/**
 	 * @throws \chillerlan\QRCode\QRCodeException
 	 */
-	protected function setPattern(){
+	protected function createData(){
 
-		// setupPositionProbePattern
-		foreach([[0, 0], [$this->pixelCount - 7, 0], [0, $this->pixelCount - 7]] as $grid){
-			$row = $grid[0];
-			$col = $grid[1];
+		if(!isset($this->errorCorrectLevel)){
+			throw new QRCodeException('Invalid error correct level '.$this->errorCorrectLevel);
+		}
 
-			for($r = -1; $r <= 7; $r++){
-				for($c = -1; $c <= 7; $c++){
+		$this->bitBuffer->clear();
 
-					if($row + $r <= -1 || $this->pixelCount <= $row + $r || $col + $c <= -1 || $this->pixelCount <= $col + $c){
-						continue;
-					}
+		$MAX_BITS = QRConst::MAX_BITS; // php5 compat
+		$MAX_BITS = $MAX_BITS[$this->typeNumber][$this->errorCorrectLevel];
 
-					$this->matrix[$row + $r][$col + $c] =
-						   (0 <= $r && $r <= 6 && ($c === 0 || $c === 6))
-						|| (0 <= $c && $c <= 6 && ($r === 0 || $r === 6))
-						|| (2 <= $c && $c <= 4 && 2 <= $r && $r <= 4);
-				}
-			}
+		/** @noinspection PhpUndefinedFieldInspection */
+		$this->bitBuffer->put($this->qrDataInterface->mode, 4);
+		/** @noinspection PhpUndefinedFieldInspection */
+		$this->bitBuffer->put(
+			$this->qrDataInterface->mode === QRConst::MODE_KANJI ? floor($this->qrDataInterface->dataLength / 2) : $this->qrDataInterface->dataLength,
+			$this->qrDataInterface->getLengthInBits($this->typeNumber)
+		);
+
+		$this->qrDataInterface->write($this->bitBuffer);
+
+		if($this->bitBuffer->length > $MAX_BITS){
+			throw new QRCodeException('code length overflow. ('.$this->bitBuffer->length.' > '.$MAX_BITS.'bit)');
 		}
 
-		// setupPositionAdjustPattern
-		$PATTERN_POSITION = QRConst::PATTERN_POSITION; // PHP5 compat
-		$pos = $PATTERN_POSITION[$this->typeNumber - 1];
-		foreach($pos as $i => $posI){
-			foreach($pos as $j => $posJ){
+		// end code.
+		if($this->bitBuffer->length + 4 <= $MAX_BITS){
+			$this->bitBuffer->put(0, 4);
+		}
 
-				if($this->matrix[$posI][$posJ] !== null){
-					continue;
-				}
+		// padding
+		while($this->bitBuffer->length % 8 !== 0){
+			$this->bitBuffer->putBit(false);
+		}
 
-				for($row = -2; $row <= 2; $row++){
-					for($col = -2; $col <= 2; $col++){
-						$this->matrix[$posI + $row][$posJ + $col] =
-							   $row === -2 || $row === 2
-							|| $col === -2 || $col === 2
-							||($row ===  0 && $col === 0);
-					}
-				}
+		// padding
+		while(true){
 
+			if($this->bitBuffer->length >= $MAX_BITS){
+				break;
 			}
-		}
 
-		// setupTimingPattern
-		for($i = 8; $i < $this->pixelCount - 8; $i++){
+			$this->bitBuffer->put(QRConst::PAD0, 8);
 
-			if($this->matrix[$i][6] !== null){
-				continue;
+			if($this->bitBuffer->length >= $MAX_BITS){
+				break;
 			}
 
-			$this->matrix[$i][6] = $this->matrix[6][$i] = $i % 2 === 0;
+			$this->bitBuffer->put(QRConst::PAD1, 8);
 		}
 
 	}
 
 	/**
-	 * @param bool $test
-	 *
-	 * @return $this
+	 * @return array
+	 * @throws \chillerlan\QRCode\QRCodeException
 	 */
-	protected function setTypeNumber($test){
-		$bits = self::getBCHTypeNumber($this->typeNumber);
+	protected function createBytes(){
+		$totalCodeCount = $maxDcCount = $maxEcCount = $offset = $index = 0;
+		$rsBlocks = Util::getRSBlocks($this->typeNumber, $this->errorCorrectLevel);
+		$rsBlockCount = count($rsBlocks);
+		$dcdata = $ecdata = array_fill(0, $rsBlockCount, null);
 
-		for($i = 0; $i < 18; $i++){
-			$a = (int)floor($i / 3);
-			$b = $i % 3 + $this->pixelCount - 8 - 3;
+		foreach($rsBlocks as $key => $value){
+			$rsBlockTotal = $value[0];
+			$rsBlockDataCount = $value[1];
 
-			$this->matrix[$a][$b] = $this->matrix[$b][$a] = !$test && (($bits >> $i) & 1) === 1;
-		}
+			$maxDcCount = max($maxDcCount, $rsBlockDataCount);
+			$maxEcCount = max($maxEcCount, $rsBlockTotal - $rsBlockDataCount);
 
-	}
+			$dcdata[$key] = array_fill(0, $rsBlockDataCount, null);
 
-	/**
-	 * @param bool $test
-	 * @param int  $pattern
-	 *
-	 * @throws \chillerlan\QRCode\QRCodeException
-	 */
-	protected function getMatrix($test, $pattern){
-		if($this->typeNumber < 1 || $this->typeNumber > 10){
-			throw new QRCodeException('Invalid type number '.$this->typeNumber);
+			foreach($dcdata[$key] as $i => &$_dcdata){
+				$bdata = $this->bitBuffer->buffer;
+				$_dcdata = 0xff & $bdata[$i + $offset];
+			}
+
+			$offset += $rsBlockDataCount;
+
+			$rsPoly = new Polynomial;
+			$modPoly = new Polynomial;
+
+			for($i = 0; $i < $rsBlockTotal - $rsBlockDataCount; $i++){
+				$modPoly->setNum([1, $modPoly->gexp($i)]);
+				$rsPoly->multiply($modPoly->num);
+			}
+
+			$rsPolyCount = count($rsPoly->num);
+			$modPoly->setNum($dcdata[$key], $rsPolyCount - 1)->mod($rsPoly->num);
+			$ecdata[$key] = array_fill(0, $rsPolyCount - 1, null);
+			$add = count($modPoly->num) - count($ecdata[$key]);
+
+			foreach($ecdata[$key] as $i => &$_ecdata){
+				$modIndex = $i + $add;
+				$_ecdata = $modIndex >= 0 ? $modPoly->num[$modIndex] : 0;
+			}
+
+			$totalCodeCount += $rsBlockTotal;
 		}
 
-		$this->pixelCount = $this->typeNumber * 4 + 17;
-		$this->matrix = array_fill(0, $this->pixelCount, array_fill(0, $this->pixelCount, null));
-		$this->setTypeInfo($test, $pattern);
+		$data = array_fill(0, $totalCodeCount, null);
 
-		if($this->typeNumber >= 7){
-			$this->setTypeNumber($test);
+		for($i = 0; $i < $maxDcCount; $i++){
+			for($key = 0; $key < $rsBlockCount; $key++){
+				if($i < count($dcdata[$key])){
+					$data[$index++] = $dcdata[$key][$i];
+				}
+			}
 		}
 
-		$this->mapData($pattern);
+		for($i = 0; $i < $maxEcCount; $i++){
+			for($key = 0; $key < $rsBlockCount; $key++){
+				if($i < count($ecdata[$key])){
+					$data[$index++] = $ecdata[$key][$i];
+				}
+			}
+		}
+
+		return $data;
 	}
 
 	/**
@@ -526,15 +496,15 @@ class QRCode{
 						$m = $row * $_col;
 
 						$MASK_PATTERN = [
-							QRConst::MASK_PATTERN000 => $a % 2,
-							QRConst::MASK_PATTERN001 => $row % 2,
-							QRConst::MASK_PATTERN010 => $_col % 3,
-							QRConst::MASK_PATTERN011 => $a % 3,
-							QRConst::MASK_PATTERN100 => (floor($row / 2) + floor($_col / 3)) % 2,
-							QRConst::MASK_PATTERN101 => $m % 2 + $m % 3,
-							QRConst::MASK_PATTERN110 => ($m % 2 + $m % 3) % 2,
-							QRConst::MASK_PATTERN111 => ($m % 3 + $a % 2) % 2,
-						][$pattern];
+							                QRConst::MASK_PATTERN000 => $a % 2,
+							                QRConst::MASK_PATTERN001 => $row % 2,
+							                QRConst::MASK_PATTERN010 => $_col % 3,
+							                QRConst::MASK_PATTERN011 => $a % 3,
+							                QRConst::MASK_PATTERN100 => (floor($row / 2) + floor($_col / 3)) % 2,
+							                QRConst::MASK_PATTERN101 => $m % 2 + $m % 3,
+							                QRConst::MASK_PATTERN110 => ($m % 2 + $m % 3) % 2,
+							                QRConst::MASK_PATTERN111 => ($m % 3 + $a % 2) % 2,
+						                ][$pattern];
 
 						if($MASK_PATTERN === 0){
 							$dark = !$dark;
@@ -566,157 +536,84 @@ class QRCode{
 	}
 
 	/**
-	 * @return $this
 	 * @throws \chillerlan\QRCode\QRCodeException
 	 */
-	protected function createData(){
-
-		if(!isset($this->errorCorrectLevel)){
-			throw new QRCodeException('Invalid error correct level '.$this->errorCorrectLevel);
-		}
-
-		$this->bitBuffer->clear();
+	protected function setPattern(){
 
-		$MAX_BITS = QRConst::MAX_BITS; // php5 compat
-		$MAX_BITS = $MAX_BITS[$this->typeNumber][$this->errorCorrectLevel];
+		// setupPositionProbePattern
+		foreach([[0, 0], [$this->pixelCount - 7, 0], [0, $this->pixelCount - 7]] as $grid){
+			$row = $grid[0];
+			$col = $grid[1];
 
-		/** @noinspection PhpUndefinedFieldInspection */
-		$this->bitBuffer->put($this->qrDataInterface->mode, 4);
-		/** @noinspection PhpUndefinedFieldInspection */
-		$this->bitBuffer->put(
-			$this->qrDataInterface->mode === QRConst::MODE_KANJI ? floor($this->qrDataInterface->dataLength / 2) : $this->qrDataInterface->dataLength,
-			$this->qrDataInterface->getLengthInBits($this->typeNumber)
-		);
+			for($r = -1; $r <= 7; $r++){
+				for($c = -1; $c <= 7; $c++){
 
-		$this->qrDataInterface->write($this->bitBuffer);
+					if($row + $r <= -1 || $this->pixelCount <= $row + $r || $col + $c <= -1 || $this->pixelCount <= $col + $c){
+						continue;
+					}
 
-		if($this->bitBuffer->length > $MAX_BITS){
-			throw new QRCodeException('code length overflow. ('.$this->bitBuffer->length.' > '.$MAX_BITS.'bit)');
+					$this->matrix[$row + $r][$col + $c] =
+						(0 <= $r && $r <= 6 && ($c === 0 || $c === 6))
+						|| (0 <= $c && $c <= 6 && ($r === 0 || $r === 6))
+						|| (2 <= $c && $c <= 4 && 2 <= $r && $r <= 4);
+				}
+			}
 		}
 
-		// end code.
-		if($this->bitBuffer->length + 4 <= $MAX_BITS){
-			$this->bitBuffer->put(0, 4);
-		}
+		// setupPositionAdjustPattern
+		$PATTERN_POSITION = QRConst::PATTERN_POSITION; // PHP5 compat
+		$pos = $PATTERN_POSITION[$this->typeNumber - 1];
+		foreach($pos as $i => $posI){
+			foreach($pos as $j => $posJ){
 
-		// padding
-		while($this->bitBuffer->length % 8 !== 0){
-			$this->bitBuffer->putBit(false);
-		}
+				if($this->matrix[$posI][$posJ] !== null){
+					continue;
+				}
 
-		// padding
-		while(true){
+				for($row = -2; $row <= 2; $row++){
+					for($col = -2; $col <= 2; $col++){
+						$this->matrix[$posI + $row][$posJ + $col] =
+							$row === -2 || $row === 2
+							|| $col === -2 || $col === 2
+							||($row ===  0 && $col === 0);
+					}
+				}
 
-			if($this->bitBuffer->length >= $MAX_BITS){
-				break;
 			}
+		}
 
-			$this->bitBuffer->put(QRConst::PAD0, 8);
+		// setupTimingPattern
+		for($i = 8; $i < $this->pixelCount - 8; $i++){
 
-			if($this->bitBuffer->length >= $MAX_BITS){
-				break;
+			if($this->matrix[$i][6] !== null){
+				continue;
 			}
 
-			$this->bitBuffer->put(QRConst::PAD1, 8);
+			$this->matrix[$i][6] = $this->matrix[6][$i] = $i % 2 === 0;
 		}
 
 	}
 
 	/**
-	 * @param int $typeNumber
-	 * @param int $errorCorrectLevel
+	 * @param bool $test
+	 * @param int  $pattern
 	 *
-	 * @return array
 	 * @throws \chillerlan\QRCode\QRCodeException
 	 */
-	protected static function getRSBlocks($typeNumber, $errorCorrectLevel){
-		// PHP5 compat
-		$RSBLOCK = QRConst::RSBLOCK;
-		$BLOCK_TABLE = QRConst::BLOCK_TABLE;
-
-		if(!isset($RSBLOCK[$errorCorrectLevel])){
-			throw new QRCodeException('$typeNumber: '.$typeNumber.' / $errorCorrectLevel: '.$errorCorrectLevel.PHP_EOL.print_r($RSBLOCK, true));
-		}
-
-		$rsBlock = $BLOCK_TABLE[($typeNumber - 1) * 4 + $RSBLOCK[$errorCorrectLevel]];
-
-		$list = [];
-		$length = count($rsBlock) / 3;
-		for($i = 0; $i < $length; $i++){
-			for($j = 0; $j < $rsBlock[$i * 3 + 0]; $j++){
-				$list[] = [$rsBlock[$i * 3 + 1], $rsBlock[$i * 3 + 2]];
-			}
-		}
-
-		return $list;
-	}
-
-	/**
-	 * @return array
-	 * @throws \chillerlan\QRCode\QRCodeException
-	 */
-	protected function createBytes(){
-		$totalCodeCount = $maxDcCount = $maxEcCount = $offset = $index = 0;
-		$rsBlocks = $this->getRSBlocks($this->typeNumber, $this->errorCorrectLevel);
-		$rsBlockCount = count($rsBlocks);
-		$dcdata = $ecdata = array_fill(0, $rsBlockCount, null);
-
-		foreach($rsBlocks as $key => $value){
-			$rsBlockTotal = $value[0];
-			$rsBlockDataCount = $value[1];
-
-			$maxDcCount = max($maxDcCount, $rsBlockDataCount);
-			$maxEcCount = max($maxEcCount, $rsBlockTotal - $rsBlockDataCount);
-
-			$dcdata[$key] = array_fill(0, $rsBlockDataCount, null);
-
-			foreach($dcdata[$key] as $i => &$_dcdata){
-				$bdata = $this->bitBuffer->buffer;
-				$_dcdata = 0xff & $bdata[$i + $offset];
-			}
-
-			$offset += $rsBlockDataCount;
-
-			$rsPoly = new Polynomial;
-			$modPoly = new Polynomial;
-
-			for($i = 0; $i < $rsBlockTotal - $rsBlockDataCount; $i++){
-				$modPoly->setNum([1, $modPoly->gexp($i)]);
-				$rsPoly->multiply($modPoly->num);
-			}
-
-			$rsPolyCount = count($rsPoly->num);
-			$modPoly->setNum($dcdata[$key], $rsPolyCount - 1)->mod($rsPoly->num);
-			$ecdata[$key] = array_fill(0, $rsPolyCount - 1, null);
-			$add = count($modPoly->num) - count($ecdata[$key]);
-
-			foreach($ecdata[$key] as $i => &$_ecdata){
-				$modIndex = $i + $add;
-				$_ecdata = $modIndex >= 0 ? $modPoly->num[$modIndex] : 0;
-			}
-
-			$totalCodeCount += $rsBlockTotal;
+	protected function getMatrix($test, $pattern){
+		if($this->typeNumber < 1 || $this->typeNumber > 10){
+			throw new QRCodeException('Invalid type number '.$this->typeNumber);
 		}
 
-		$data = array_fill(0, $totalCodeCount, null);
-
-		for($i = 0; $i < $maxDcCount; $i++){
-			for($key = 0; $key < $rsBlockCount; $key++){
-				if($i < count($dcdata[$key])){
-					$data[$index++] = $dcdata[$key][$i];
-				}
-			}
-		}
+		$this->pixelCount = $this->typeNumber * 4 + 17;
+		$this->matrix = array_fill(0, $this->pixelCount, array_fill(0, $this->pixelCount, null));
+		$this->setTypeInfo($test, $pattern);
 
-		for($i = 0; $i < $maxEcCount; $i++){
-			for($key = 0; $key < $rsBlockCount; $key++){
-				if($i < count($ecdata[$key])){
-					$data[$index++] = $ecdata[$key][$i];
-				}
-			}
+		if($this->typeNumber >= 7){
+			$this->setTypeNumber($test);
 		}
 
-		return $data;
+		$this->mapData($pattern);
 	}
 
 }

+ 100 - 0
src/Util.php

@@ -85,4 +85,104 @@ class Util{
 		return true;
 	}
 
+	/**
+	 * @param int $data
+	 *
+	 * @return int
+	 */
+	public static function getBCHTypeInfo($data){
+		$d = $data << 10;
+
+		while(self::getBCHDigit($d) - self::getBCHDigit(QRConst::G15) >= 0){
+			$d ^= (QRConst::G15 << (self::getBCHDigit($d) - self::getBCHDigit(QRConst::G15)));
+		}
+
+		return (($data << 10)|$d)^QRConst::G15_MASK;
+	}
+
+	/**
+	 * @param int $data
+	 *
+	 * @return int
+	 */
+	public static function getBCHTypeNumber($data){
+		$d = $data << 12;
+
+		while(self::getBCHDigit($d) - self::getBCHDigit(QRConst::G18) >= 0){
+			$d ^= (QRConst::G18 << (self::getBCHDigit($d) - self::getBCHDigit(QRConst::G18)));
+		}
+
+		return ($data << 12)|$d;
+	}
+
+	/**
+	 * @param int $data
+	 *
+	 * @return int
+	 */
+	public static function getBCHDigit($data){
+		$digit = 0;
+
+		while($data !== 0){
+			$digit++;
+			$data >>= 1;
+		}
+
+		return $digit;
+	}
+
+	/**
+	 * @param int $typeNumber
+	 * @param int $errorCorrectLevel
+	 *
+	 * @return array
+	 * @throws \chillerlan\QRCode\QRCodeException
+	 */
+	public static function getRSBlocks($typeNumber, $errorCorrectLevel){
+		// PHP5 compat
+		$RSBLOCK = QRConst::RSBLOCK;
+		$BLOCK_TABLE = QRConst::BLOCK_TABLE;
+
+		if(!isset($RSBLOCK[$errorCorrectLevel])){
+			throw new QRCodeException('$typeNumber: '.$typeNumber.' / $errorCorrectLevel: '.$errorCorrectLevel.PHP_EOL.print_r($RSBLOCK, true));
+		}
+
+		$rsBlock = $BLOCK_TABLE[($typeNumber - 1) * 4 + $RSBLOCK[$errorCorrectLevel]];
+
+		$list = [];
+		$length = count($rsBlock) / 3;
+		for($i = 0; $i < $length; $i++){
+			for($j = 0; $j < $rsBlock[$i * 3 + 0]; $j++){
+				$list[] = [$rsBlock[$i * 3 + 1], $rsBlock[$i * 3 + 2]];
+			}
+		}
+
+		return $list;
+	}
+
+	/**
+	 * @param int $typeNumber
+	 * @param int $mode
+	 * @param int $ecLevel
+	 *
+	 * @return int
+	 * @throws \chillerlan\QRCode\QRCodeException
+	 */
+	public static function getMaxLength($typeNumber, $mode, $ecLevel){
+		$RSBLOCK = QRConst::RSBLOCK;
+		$MAX_LENGTH = QRConst::MAX_LENGTH;
+		$MODE = QRConst::MODE;
+
+		if(!isset($RSBLOCK[$ecLevel])){
+			throw new QRCodeException('$_err: '.$ecLevel);
+		}
+
+		if(!isset($MODE[$mode])){
+			throw new QRCodeException('$_mode: '.$mode);
+		}
+
+		return $MAX_LENGTH[$typeNumber - 1][$RSBLOCK[$ecLevel]][$MODE[$mode]];
+	}
+
+
 }