mirror of
https://github.com/chillerlan/php-qrcode.git
synced 2026-09-12 02:36:28 +00:00
🚿 mask pattern cleanup
This commit is contained in:
+16
-10
@@ -70,22 +70,28 @@ final class MaskPattern{
|
||||
/**
|
||||
* Returns a closure that applies the mask for the chosen mask pattern.
|
||||
*
|
||||
* Note that some versions of the QR code standard have had errors in the section about mask patterns.
|
||||
* The information below has been corrected.
|
||||
* Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations
|
||||
* of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,
|
||||
* including areas used for finder patterns, timing patterns, etc. These areas should be unused
|
||||
* after the point they are unmasked anyway.
|
||||
*
|
||||
* Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position
|
||||
* and j is row position. In fact, as the text says, i is row position and j is column position.
|
||||
*
|
||||
* @see https://www.thonky.com/qr-code-tutorial/mask-patterns
|
||||
* @see https://github.com/zxing/zxing/blob/e9e2bd280bcaeabd59d0f955798384fe6c018a6c/core/src/main/java/com/google/zxing/qrcode/decoder/DataMask.java#L32-L117
|
||||
*/
|
||||
public function getMask():Closure{
|
||||
// $x = column (width), $y = row (height)
|
||||
return [
|
||||
self::PATTERN_000 => fn(int $x, int $y):int => ($x + $y) % 2,
|
||||
self::PATTERN_001 => fn(int $x, int $y):int => $y % 2,
|
||||
self::PATTERN_010 => fn(int $x, int $y):int => $x % 3,
|
||||
self::PATTERN_011 => fn(int $x, int $y):int => ($x + $y) % 3,
|
||||
self::PATTERN_100 => fn(int $x, int $y):int => ((int)($y / 2) + (int)($x / 3)) % 2,
|
||||
self::PATTERN_101 => fn(int $x, int $y):int => (($x * $y) % 2) + (($x * $y) % 3),
|
||||
self::PATTERN_110 => fn(int $x, int $y):int => ((($x * $y) % 2) + (($x * $y) % 3)) % 2,
|
||||
self::PATTERN_111 => fn(int $x, int $y):int => ((($x * $y) % 3) + (($x + $y) % 2)) % 2,
|
||||
self::PATTERN_000 => fn(int $x, int $y):bool => (($x + $y) % 2) === 0,
|
||||
self::PATTERN_001 => fn(int $x, int $y):bool => ($y % 2) === 0,
|
||||
self::PATTERN_010 => fn(int $x, int $y):bool => ($x % 3) === 0,
|
||||
self::PATTERN_011 => fn(int $x, int $y):bool => (($x + $y) % 3) === 0,
|
||||
self::PATTERN_100 => fn(int $x, int $y):bool => (((int)($y / 2) + (int)($x / 3)) % 2) === 0,
|
||||
self::PATTERN_101 => fn(int $x, int $y):bool => ($x * $y) % 6 === 0, // ((($x * $y) % 2) + (($x * $y) % 3)) === 0,
|
||||
self::PATTERN_110 => fn(int $x, int $y):bool => (($x * $y) % 6) < 3, // (((($x * $y) % 2) + (($x * $y) % 3)) % 2) === 0,
|
||||
self::PATTERN_111 => fn(int $x, int $y):bool => (($x + $y + (($x * $y) % 3)) % 2) === 0, // (((($x * $y) % 3) + (($x + $y) % 2)) % 2) === 0,
|
||||
][$this->maskPattern];
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ final class MaskPatternTester{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for each group of five or more same-colored modules in a row (or column)
|
||||
* Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
|
||||
* give penalty to them. Example: 00000 or 11111.
|
||||
*/
|
||||
private function testLevel1(array $m, int $size):int{
|
||||
$penalty = 0;
|
||||
@@ -111,7 +112,9 @@ final class MaskPatternTester{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for each 2x2 area of same-colored modules in the matrix
|
||||
* Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
|
||||
* penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a
|
||||
* penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block.
|
||||
*/
|
||||
private function testLevel2(array $m, int $size):int{
|
||||
$penalty = 0;
|
||||
@@ -142,7 +145,9 @@ final class MaskPatternTester{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are patterns that look similar to the finder patterns (1:1:3:1:1 ratio)
|
||||
* Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4
|
||||
* starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we
|
||||
* find patterns like 000010111010000, we give penalty once.
|
||||
*/
|
||||
private function testLevel3(array $m, int $size):int{
|
||||
$penalties = 0;
|
||||
@@ -183,7 +188,8 @@ final class MaskPatternTester{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if more than half of the modules are dark or light, with a larger penalty for a larger difference
|
||||
* Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
|
||||
* penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance.
|
||||
*/
|
||||
private function testLevel4(array $m, int $size):float{
|
||||
$count = 0;
|
||||
|
||||
@@ -571,7 +571,7 @@ final class QRMatrix{
|
||||
|
||||
foreach($this->matrix as $y => &$row){
|
||||
foreach($row as $x => &$val){
|
||||
if($mask($x, $y) === 0 && ($val & $this::M_DATA) === $this::M_DATA){
|
||||
if($mask($x, $y) && ($val & $this::M_DATA) === $this::M_DATA){
|
||||
$val ^= $this::IS_DARK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,23 +182,15 @@ final class BitMatrix{
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations
|
||||
* of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,
|
||||
* including areas used for finder patterns, timing patterns, etc. These areas should be unused
|
||||
* after the point they are unmasked anyway.</p>
|
||||
*
|
||||
* <p>Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position
|
||||
* and j is row position. In fact, as the text says, i is row position and j is column position.</p>
|
||||
*
|
||||
* <p>Implementations of this method reverse the data masking process applied to a QR Code and
|
||||
* make its bits ready to read.</p>
|
||||
* Implementations of this method reverse the data masking process applied to a QR Code and
|
||||
* make its bits ready to read.
|
||||
*/
|
||||
public function unmask(int $dimension, MaskPattern $maskPattern):void{
|
||||
$mask = $maskPattern->getMask();
|
||||
|
||||
for($y = 0; $y < $dimension; $y++){
|
||||
for($x = 0; $x < $dimension; $x++){
|
||||
if($mask($x, $y) === 0){
|
||||
if($mask($x, $y)){
|
||||
$this->flip($x, $y);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user