codemasher 4 лет назад
Родитель
Сommit
f4401a4b2b

+ 2 - 2
src/Decoder/Binarizer.php

@@ -36,8 +36,8 @@ final class Binarizer{
 	// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
 	// So this is the smallest dimension in each axis we can accept.
 	private const BLOCK_SIZE_POWER  = 3;
-	private const BLOCK_SIZE        = 8; // ...0100...00
-	private const BLOCK_SIZE_MASK   = 7;   // ...0011...11
+	private const BLOCK_SIZE        = 8;  // ...0100...00
+	private const BLOCK_SIZE_MASK   = 7;  // ...0011...11
 	private const MINIMUM_DIMENSION = 40;
 	private const MIN_DYNAMIC_RANGE = 24;
 

+ 1 - 2
src/Decoder/BitMatrix.php

@@ -13,7 +13,6 @@ namespace chillerlan\QRCode\Decoder;
 
 use chillerlan\QRCode\Common\{MaskPattern, Version};
 use InvalidArgumentException;
-use function chillerlan\QRCode\Common\uRShift;
 use function array_fill, count;
 
 final class BitMatrix{
@@ -110,7 +109,7 @@ final class BitMatrix{
 
 		$this->bits[$offset] ??= 0;
 
-		return (uRShift($this->bits[$offset], ($x & 0x1f)) & 1) !== 0;
+		return (BitMatrixParser::uRShift($this->bits[$offset], ($x & 0x1f)) & 1) !== 0;
 	}
 
 	/**

+ 28 - 5
src/Decoder/BitMatrixParser.php

@@ -13,8 +13,7 @@ namespace chillerlan\QRCode\Decoder;
 
 use RuntimeException;
 use chillerlan\QRCode\Common\{Version, FormatInformation};
-use function chillerlan\QRCode\Common\numBitsDiffering;
-use const PHP_INT_MAX;
+use const PHP_INT_MAX, PHP_INT_SIZE;
 
 /**
  * @author Sean Owen
@@ -219,7 +218,7 @@ final class BitMatrixParser{
 				return new FormatInformation($maskedBits);
 			}
 
-			$bitsDifference = numBitsDiffering($maskedFormatInfo1, $dataBits);
+			$bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $dataBits);
 
 			if($bitsDifference < $bestDifference){
 				$bestFormatInfo = $maskedBits;
@@ -228,7 +227,7 @@ final class BitMatrixParser{
 
 			if($maskedFormatInfo1 !== $maskedFormatInfo2){
 				// also try the other option
-				$bitsDifference = numBitsDiffering($maskedFormatInfo2, $dataBits);
+				$bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $dataBits);
 
 				if($bitsDifference < $bestDifference){
 					$bestFormatInfo = $maskedBits;
@@ -319,7 +318,7 @@ final class BitMatrixParser{
 			// Otherwise see if this is the closest to a real version info bit string
 			// we have seen so far
 			/** @phan-suppress-next-line PhanTypeMismatchArgumentNullable ($targetVersionPattern is never null here) */
-			$bitsDifference = numBitsDiffering($versionBits, $targetVersionPattern);
+			$bitsDifference = self::numBitsDiffering($versionBits, $targetVersionPattern);
 
 			if($bitsDifference < $bestDifference){
 				$bestVersion    = $i;
@@ -336,4 +335,28 @@ final class BitMatrixParser{
 		return null;
 	}
 
+	public static function uRShift(int $a, int $b):int{
+
+		if($b === 0){
+			return $a;
+		}
+
+		return ($a >> $b) & ~((1 << (8 * PHP_INT_SIZE - 1)) >> ($b - 1));
+	}
+
+	private static function numBitsDiffering(int $a, int $b):int{
+		// a now has a 1 bit exactly where its bit differs with b's
+		$a ^= $b;
+		// Offset i holds the number of 1 bits in the binary representation of i
+		$BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];
+		// Count bits set quickly with a series of lookups:
+		$count = 0;
+
+		for($i = 0; $i < 32; $i += 4){
+			$count += $BITS_SET_IN_HALF_BYTE[self::uRShift($a, $i) & 0x0F];
+		}
+
+		return $count;
+	}
+
 }

+ 6 - 2
src/Decoder/LuminanceSource.php

@@ -12,7 +12,7 @@
 namespace chillerlan\QRCode\Decoder;
 
 use InvalidArgumentException;
-use function chillerlan\QRCode\Common\arraycopy;
+use function array_slice, array_splice;
 
 /**
  * The purpose of this class hierarchy is to abstract different bitmap implementations across
@@ -82,7 +82,11 @@ abstract class LuminanceSource{
 			throw new InvalidArgumentException('Requested row is outside the image: '.$y);
 		}
 
-		return arraycopy($this->luminances, $y * $this->width, [], 0, $this->width);
+		$arr = [];
+
+		array_splice($arr, 0, $this->width, array_slice($this->luminances, $y * $this->width, $this->width));
+
+		return $arr;
 	}
 
 	/**

+ 1 - 4
src/Detector/AlignmentPatternFinder.php

@@ -14,7 +14,6 @@ namespace chillerlan\QRCode\Detector;
 use chillerlan\QRCode\Decoder\BitMatrix;
 use function abs, count;
 
-
 /**
  * <p>This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder
  * patterns but are smaller and appear at regular intervals throughout the image.</p>
@@ -35,7 +34,6 @@ final class AlignmentPatternFinder{
 	private float     $moduleSize;
 	/** @var \chillerlan\QRCode\Detector\AlignmentPattern[] */
 	private array $possibleCenters;
-	private array $crossCheckStateCount;
 
 	/**
 	 * <p>Creates a finder that will look in a portion of the whole image.</p>
@@ -47,7 +45,6 @@ final class AlignmentPatternFinder{
 		$this->bitMatrix            = $image;
 		$this->moduleSize           = $moduleSize;
 		$this->possibleCenters      = [];
-		$this->crossCheckStateCount = [];
 	}
 
 	/**
@@ -228,7 +225,7 @@ final class AlignmentPatternFinder{
 	 */
 	private function crossCheckVertical(int $startI, int $centerJ, int $maxCount, int $originalStateCountTotal):?float{
 		$maxI          = $this->bitMatrix->getDimension();
-		$stateCount    = $this->crossCheckStateCount;
+		$stateCount    = [];
 		$stateCount[0] = 0;
 		$stateCount[1] = 0;
 		$stateCount[2] = 0;

+ 4 - 5
src/Detector/Detector.php

@@ -15,7 +15,6 @@ use RuntimeException;
 use chillerlan\QRCode\Common\Version;
 use chillerlan\QRCode\Decoder\BitMatrix;
 use function abs, is_nan, max, min, round;
-use function chillerlan\QRCode\Common\distance;
 use const NAN;
 
 /**
@@ -210,7 +209,7 @@ final class Detector{
 			if(($state === 1) === $this->bitMatrix->get($realX, $realY)){
 
 				if($state === 2){
-					return distance($x, $y, $fromX, $fromY);
+					return FinderPattern::distance($x, $y, $fromX, $fromY);
 				}
 
 				$state++;
@@ -233,7 +232,7 @@ final class Detector{
 		// is "white" so this last po$at (toX+xStep,toY) is the right ending. This is really a
 		// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
 		if($state === 2){
-			return distance($toX + $xstep, $toY, $fromX, $fromY);
+			return FinderPattern::distance($toX + $xstep, $toY, $fromX, $fromY);
 		}
 
 		// else we didn't find even black-white-black; no estimate is really possible
@@ -252,8 +251,8 @@ final class Detector{
 		FinderPattern $bottomLeft,
 		float $moduleSize
 	):int{
-		$tltrCentersDimension = (int)round($topLeft->distance($topRight) / $moduleSize);
-		$tlblCentersDimension = (int)round($topLeft->distance($bottomLeft) / $moduleSize);
+		$tltrCentersDimension = (int)round($topLeft->getDistance($topRight) / $moduleSize);
+		$tlblCentersDimension = (int)round($topLeft->getDistance($bottomLeft) / $moduleSize);
 		$dimension            = (int)((($tltrCentersDimension + $tlblCentersDimension) / 2) + 7);
 
 		switch($dimension % 4){

+ 18 - 7
src/Detector/FinderPattern.php

@@ -11,7 +11,7 @@
 
 namespace chillerlan\QRCode\Detector;
 
-use function chillerlan\QRCode\Common\{distance, squaredDistance};
+use function sqrt;
 
 /**
  * <p>Encapsulates a finder pattern, which are the three square patterns found in
@@ -24,10 +24,10 @@ final class FinderPattern extends ResultPoint{
 
 	private int $count;
 
-	public function __construct(float $posX, float $posY, float $estimatedModuleSize, int $count = 1){
+	public function __construct(float $posX, float $posY, float $estimatedModuleSize, int $count = null){
 		parent::__construct($posX, $posY, $estimatedModuleSize);
 
-		$this->count = $count;
+		$this->count = $count ?? 1;
 	}
 
 	public function getCount():int{
@@ -39,15 +39,15 @@ final class FinderPattern extends ResultPoint{
 	 *
 	 * @return float distance between two points
 	 */
-	public function distance(FinderPattern $b):float{
-		return distance($this->getX(), $this->getY(), $b->getX(), $b->getY());
+	public function getDistance(FinderPattern $b):float{
+		return self::distance($this->x, $this->y, $b->x, $b->y);
 	}
 
 	/**
 	 * Get square of distance between a and b.
 	 */
-	public function squaredDistance(FinderPattern $b):float{
-		return squaredDistance($this->getX(), $this->getY(), $b->getX(), $b->getY());
+	public function getSquaredDistance(FinderPattern $b):float{
+		return self::squaredDistance($this->x, $this->y, $b->x, $b->y);
 	}
 
 	/**
@@ -66,4 +66,15 @@ final class FinderPattern extends ResultPoint{
 		);
 	}
 
+	private static function squaredDistance(float $aX, float $aY, float $bX, float $bY):float{
+		$xDiff = $aX - $bX;
+		$yDiff = $aY - $bY;
+
+		return $xDiff * $xDiff + $yDiff * $yDiff;
+	}
+
+	public static function distance(float $aX, float $aY, float $bX, float $bY):float{
+		return sqrt(self::squaredDistance($aX, $aY, $bX, $bY));
+	}
+
 }

+ 8 - 11
src/Detector/FinderPatternFinder.php

@@ -35,8 +35,6 @@ final class FinderPatternFinder{
 	/** @var \chillerlan\QRCode\Detector\FinderPattern[] */
 	private array $possibleCenters;
 	private bool  $hasSkipped = false;
-	/** @var int[] */
-	private array $crossCheckStateCount;
 
 	/**
 	 * <p>Creates a finder that will search the image for three finder patterns.</p>
@@ -44,9 +42,8 @@ final class FinderPatternFinder{
 	 * @param BitMatrix $bitMatrix image to search
 	 */
 	public function __construct(BitMatrix $bitMatrix){
-		$this->bitMatrix            = $bitMatrix;
-		$this->possibleCenters      = [];
-		$this->crossCheckStateCount = $this->getCrossCheckStateCount();
+		$this->bitMatrix       = $bitMatrix;
+		$this->possibleCenters = [];
 	}
 
 	/**
@@ -649,7 +646,7 @@ final class FinderPatternFinder{
 
 			for($j = $i + 1; $j < $startSize - 1; $j++){
 				$fpj      = $this->possibleCenters[$j];
-				$squares0 = $fpi->squaredDistance($fpj);
+				$squares0 = $fpi->getSquaredDistance($fpj);
 
 				for($k = $j + 1; $k < $startSize; $k++){
 					$fpk           = $this->possibleCenters[$k];
@@ -661,8 +658,8 @@ final class FinderPatternFinder{
 					}
 
 					$a = $squares0;
-					$b = $fpj->squaredDistance($fpk);
-					$c = $fpi->squaredDistance($fpk);
+					$b = $fpj->getSquaredDistance($fpk);
+					$c = $fpi->getSquaredDistance($fpk);
 
 					// sorts ascending - inlined
 					if($a < $b){
@@ -734,9 +731,9 @@ final class FinderPatternFinder{
 	private function orderBestPatterns(array $patterns):array{
 
 		// Find distances between pattern centers
-		$zeroOneDistance = $patterns[0]->distance($patterns[1]);
-		$oneTwoDistance  = $patterns[1]->distance($patterns[2]);
-		$zeroTwoDistance = $patterns[0]->distance($patterns[2]);
+		$zeroOneDistance = $patterns[0]->getDistance($patterns[1]);
+		$oneTwoDistance  = $patterns[1]->getDistance($patterns[2]);
+		$zeroTwoDistance = $patterns[0]->getDistance($patterns[2]);
 
 		// Assume one closest to other two is B; A and C will just be guesses at first
 		if($oneTwoDistance >= $zeroOneDistance && $oneTwoDistance >= $zeroTwoDistance){

+ 2 - 2
src/Detector/GridSampler.php

@@ -132,10 +132,10 @@ final class GridSampler{
 
 		for($y = 0; $y < $dimension; $y++){
 			$max    = count($points);
-			$iValue = (float)$y + 0.5;
+			$iValue = $y + 0.5;
 
 			for($x = 0; $x < $max; $x += 2){
-				$points[$x]     = (float)($x / 2) + 0.5;
+				$points[$x]     = ($x / 2) + 0.5;
 				$points[$x + 1] = $iValue;
 			}
 

+ 2 - 2
src/Detector/ResultPoint.php

@@ -32,11 +32,11 @@ abstract class ResultPoint{
 	}
 
 	public function getX():float{
-		return (float)$this->x;
+		return $this->x;
 	}
 
 	public function getY():float{
-		return (float)$this->y;
+		return $this->y;
 	}
 
 	public function getEstimatedModuleSize():float{