This commit is contained in:
TheXamlGuy
2024-04-26 23:05:36 +01:00
parent 9f90ef693d
commit bc55c4649b
206 changed files with 3106 additions and 3204 deletions
@@ -2,12 +2,12 @@ namespace Gma.QrCodeNet.Encoding.Masking;
public enum MaskPatternType
{
Type0 = 0,
Type1 = 1,
Type2 = 2,
Type3 = 3,
Type4 = 4,
Type5 = 5,
Type6 = 6,
Type7 = 7
}
Type0 = 0,
Type1 = 1,
Type2 = 2,
Type3 = 3,
Type4 = 4,
Type5 = 5,
Type6 = 6,
Type7 = 7
}
@@ -1,44 +1,43 @@
using System;
using Gma.QrCodeNet.Encoding.EncodingRegion;
namespace Gma.QrCodeNet.Encoding.Masking;
public static class MatrixExtensions
{
public static TriStateMatrix Xor(this TriStateMatrix first, Pattern second, ErrorCorrectionLevel errorLevel)
{
TriStateMatrix result = XorMatrix(first, second);
result.EmbedFormatInformation(errorLevel, second);
return result;
}
public static TriStateMatrix Xor(this TriStateMatrix first, Pattern second, ErrorCorrectionLevel errorLevel)
{
TriStateMatrix result = XorMatrix(first, second);
result.EmbedFormatInformation(errorLevel, second);
return result;
}
private static TriStateMatrix XorMatrix(TriStateMatrix first, BitMatrix second)
{
int width = first.Width;
TriStateMatrix maskedMatrix = new(width);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < width; y++)
{
MatrixStatus states = first.MStatus(x, y);
switch (states)
{
case MatrixStatus.NoMask:
maskedMatrix[x, y, MatrixStatus.NoMask] = first[x, y];
break;
private static TriStateMatrix XorMatrix(TriStateMatrix first, BitMatrix second)
{
int width = first.Width;
TriStateMatrix maskedMatrix = new(width);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < width; y++)
{
MatrixStatus states = first.MStatus(x, y);
switch (states)
{
case MatrixStatus.NoMask:
maskedMatrix[x, y, MatrixStatus.NoMask] = first[x, y];
break;
case MatrixStatus.Data:
maskedMatrix[x, y, MatrixStatus.Data] = first[x, y] ^ second[x, y];
break;
case MatrixStatus.Data:
maskedMatrix[x, y, MatrixStatus.Data] = first[x, y] ^ second[x, y];
break;
default:
throw new ArgumentException($"{nameof(TriStateMatrix)} has None value cell.", nameof(first));
}
}
}
default:
throw new ArgumentException($"{nameof(TriStateMatrix)} has None value cell.", nameof(first));
}
}
}
return maskedMatrix;
}
return maskedMatrix;
}
public static TriStateMatrix Apply(this TriStateMatrix matrix, Pattern pattern, ErrorCorrectionLevel errorLevel) => matrix.Xor(pattern, errorLevel);
}
public static TriStateMatrix Apply(this TriStateMatrix matrix, Pattern pattern, ErrorCorrectionLevel errorLevel) => matrix.Xor(pattern, errorLevel);
}
@@ -1,13 +1,11 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
public abstract class Pattern : BitMatrix
{
public override int Width => throw new NotSupportedException();
public override int Height => throw new NotSupportedException();
public override int Width => throw new NotSupportedException();
public override int Height => throw new NotSupportedException();
public override bool[,] InternalArray => throw new NotImplementedException();
public override bool[,] InternalArray => throw new NotImplementedException();
public abstract MaskPatternType MaskPatternType { get; }
}
public abstract MaskPatternType MaskPatternType { get; }
}
@@ -1,14 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern0 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type0;
public override MaskPatternType MaskPatternType => MaskPatternType.Type0;
public override bool this[int i, int j]
{
get => (j + i) % 2 == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => (j + i) % 2 == 0;
set => throw new NotSupportedException();
}
}
@@ -1,14 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern1 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type1;
public override MaskPatternType MaskPatternType => MaskPatternType.Type1;
public override bool this[int i, int j]
{
get => j % 2 == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => j % 2 == 0;
set => throw new NotSupportedException();
}
}
@@ -1,14 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern2 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type2;
public override MaskPatternType MaskPatternType => MaskPatternType.Type2;
public override bool this[int i, int j]
{
get => i % 3 == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => i % 3 == 0;
set => throw new NotSupportedException();
}
}
@@ -1,14 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern3 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type3;
public override MaskPatternType MaskPatternType => MaskPatternType.Type3;
public override bool this[int i, int j]
{
get => (j + i) % 3 == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => (j + i) % 3 == 0;
set => throw new NotSupportedException();
}
}
@@ -1,14 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern4 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type4;
public override MaskPatternType MaskPatternType => MaskPatternType.Type4;
public override bool this[int i, int j]
{
get => ((j / 2) + (i / 3)) % 2 == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => ((j / 2) + (i / 3)) % 2 == 0;
set => throw new NotSupportedException();
}
}
@@ -1,14 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern5 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type5;
public override MaskPatternType MaskPatternType => MaskPatternType.Type5;
public override bool this[int i, int j]
{
get => (((i * j) % 2) + ((i * j) % 3)) == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => (((i * j) % 2) + ((i * j) % 3)) == 0;
set => throw new NotSupportedException();
}
}
@@ -1,13 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern6 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type6;
public override MaskPatternType MaskPatternType => MaskPatternType.Type6;
public override bool this[int i, int j]
{
get => ((((i * j) % 2) + ((i * j) % 3)) % 2) == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => ((((i * j) % 2) + ((i * j) % 3)) % 2) == 0;
set => throw new NotSupportedException();
}
}
@@ -1,14 +1,12 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class Pattern7 : Pattern
{
public override MaskPatternType MaskPatternType => MaskPatternType.Type7;
public override MaskPatternType MaskPatternType => MaskPatternType.Type7;
public override bool this[int i, int j]
{
get => (((i * j) % 3) + (((i + j) % 2) % 2)) == 0;
set => throw new NotSupportedException();
}
}
public override bool this[int i, int j]
{
get => (((i * j) % 3) + (((i + j) % 2) % 2)) == 0;
set => throw new NotSupportedException();
}
}
@@ -1,31 +1,28 @@
using System;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.Masking;
internal class PatternFactory
{
internal Pattern CreateByType(MaskPatternType maskPatternType)
{
return maskPatternType switch
{
MaskPatternType.Type0 => new Pattern0(),
MaskPatternType.Type1 => new Pattern1(),
MaskPatternType.Type2 => new Pattern2(),
MaskPatternType.Type3 => new Pattern3(),
MaskPatternType.Type4 => new Pattern4(),
MaskPatternType.Type5 => new Pattern5(),
MaskPatternType.Type6 => new Pattern6(),
MaskPatternType.Type7 => new Pattern7(),
_ => throw new NotSupportedException("This should never happen.")
};
}
internal Pattern CreateByType(MaskPatternType maskPatternType)
{
return maskPatternType switch
{
MaskPatternType.Type0 => new Pattern0(),
MaskPatternType.Type1 => new Pattern1(),
MaskPatternType.Type2 => new Pattern2(),
MaskPatternType.Type3 => new Pattern3(),
MaskPatternType.Type4 => new Pattern4(),
MaskPatternType.Type5 => new Pattern5(),
MaskPatternType.Type6 => new Pattern6(),
MaskPatternType.Type7 => new Pattern7(),
_ => throw new NotSupportedException("This should never happen.")
};
}
internal IEnumerable<Pattern> AllPatterns()
{
foreach (MaskPatternType patternType in Enum.GetValues(typeof(MaskPatternType)))
{
yield return CreateByType(patternType);
}
}
}
internal IEnumerable<Pattern> AllPatterns()
{
foreach (MaskPatternType patternType in Enum.GetValues(typeof(MaskPatternType)))
{
yield return CreateByType(patternType);
}
}
}
@@ -1,36 +1,34 @@
using System.Linq;
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
internal static class MatrixScoreCalculator
{
internal static BitMatrix GetLowestPenaltyMatrix(this TriStateMatrix matrix, ErrorCorrectionLevel errorLevel)
{
PatternFactory patternFactory = new();
int score = int.MaxValue;
int tempScore;
TriStateMatrix result = new(matrix.Width);
TriStateMatrix triMatrix;
foreach (Pattern pattern in patternFactory.AllPatterns())
{
triMatrix = matrix.Apply(pattern, errorLevel);
tempScore = triMatrix.PenaltyScore();
if (tempScore < score)
{
score = tempScore;
result = triMatrix;
}
}
internal static BitMatrix GetLowestPenaltyMatrix(this TriStateMatrix matrix, ErrorCorrectionLevel errorLevel)
{
PatternFactory patternFactory = new();
int score = int.MaxValue;
int tempScore;
TriStateMatrix result = new(matrix.Width);
TriStateMatrix triMatrix;
foreach (Pattern pattern in patternFactory.AllPatterns())
{
triMatrix = matrix.Apply(pattern, errorLevel);
tempScore = triMatrix.PenaltyScore();
if (tempScore < score)
{
score = tempScore;
result = triMatrix;
}
}
return result;
}
return result;
}
internal static int PenaltyScore(this BitMatrix matrix)
{
PenaltyFactory penaltyFactory = new();
return
penaltyFactory
.AllRules()
.Sum(penalty => penalty.PenaltyCalculate(matrix));
}
}
internal static int PenaltyScore(this BitMatrix matrix)
{
PenaltyFactory penaltyFactory = new();
return
penaltyFactory
.AllRules()
.Sum(penalty => penalty.PenaltyCalculate(matrix));
}
}
@@ -2,5 +2,5 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
public abstract class Penalty
{
internal abstract int PenaltyCalculate(BitMatrix matrix);
}
internal abstract int PenaltyCalculate(BitMatrix matrix);
}
@@ -5,81 +5,81 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
/// </summary>
internal class Penalty1 : Penalty
{
/// <summary>
/// Calculate penalty value for first rule.
/// </summary>
internal override int PenaltyCalculate(BitMatrix matrix)
{
int penaltyValue = PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
return penaltyValue;
}
/// <summary>
/// Calculate penalty value for first rule.
/// </summary>
internal override int PenaltyCalculate(BitMatrix matrix)
{
int penaltyValue = PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
return penaltyValue;
}
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
{
int penalty = 0;
int width = matrix.Width;
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
{
int penalty = 0;
int width = matrix.Width;
int i = 0;
int j = 0;
int i = 0;
int j = 0;
while (i < width)
{
while (j < width - 4)
{
bool preBit = isHorizontal
? matrix[j + 4, i]
: matrix[i, j + 4];
int numSameBitCell = 1;
while (i < width)
{
while (j < width - 4)
{
bool preBit = isHorizontal
? matrix[j + 4, i]
: matrix[i, j + 4];
int numSameBitCell = 1;
for (int x = 1; x <= 4; x++)
{
bool bit = isHorizontal
? matrix[j + 4 - x, i]
: matrix[i, j + 4 - x];
if (bit == preBit)
{
numSameBitCell++;
}
else
{
break;
}
}
for (int x = 1; x <= 4; x++)
{
bool bit = isHorizontal
? matrix[j + 4 - x, i]
: matrix[i, j + 4 - x];
if (bit == preBit)
{
numSameBitCell++;
}
else
{
break;
}
}
if (numSameBitCell == 1)
{
j += 4;
}
else
{
int x = 5;
while ((j + x) < width)
{
bool bit = isHorizontal
? matrix[j + x, i]
: matrix[i, j + x];
if (bit == preBit)
{
numSameBitCell++;
}
else
{
break;
}
x++;
}
if (numSameBitCell >= 5)
{
penalty += (3 + (numSameBitCell - 5));
}
if (numSameBitCell == 1)
{
j += 4;
}
else
{
int x = 5;
while ((j + x) < width)
{
bool bit = isHorizontal
? matrix[j + x, i]
: matrix[i, j + x];
if (bit == preBit)
{
numSameBitCell++;
}
else
{
break;
}
x++;
}
if (numSameBitCell >= 5)
{
penalty += (3 + (numSameBitCell - 5));
}
j += x;
}
}
j = 0;
i++;
}
j += x;
}
}
j = 0;
i++;
}
return penalty;
}
}
return penalty;
}
}
@@ -5,47 +5,47 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
/// </summary>
internal class Penalty2 : Penalty
{
internal override int PenaltyCalculate(BitMatrix matrix)
{
int width = matrix.Width;
int x = 0;
int y = 0;
int penalty = 0;
internal override int PenaltyCalculate(BitMatrix matrix)
{
int width = matrix.Width;
int x = 0;
int y = 0;
int penalty = 0;
while (y < (width - 1))
{
while (x < (width - 1))
{
bool topR = matrix[x + 1, y];
while (y < (width - 1))
{
while (x < (width - 1))
{
bool topR = matrix[x + 1, y];
if (topR == matrix[x + 1, y + 1]) // Bottom Right
{
if (topR == matrix[x, y + 1]) // Bottom Left
{
if (topR == matrix[x, y]) // Top Left
{
penalty += 3;
x += 1;
}
else
{
x += 1;
}
}
else
{
x += 1;
}
}
else
{
x += 2;
}
}
if (topR == matrix[x + 1, y + 1]) // Bottom Right
{
if (topR == matrix[x, y + 1]) // Bottom Left
{
if (topR == matrix[x, y]) // Top Left
{
penalty += 3;
x += 1;
}
else
{
x += 1;
}
}
else
{
x += 1;
}
}
else
{
x += 2;
}
}
x = 0;
y++;
}
return penalty;
}
}
x = 0;
y++;
}
return penalty;
}
}
@@ -5,137 +5,137 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
/// </summary>
internal class Penalty3 : Penalty
{
/// <summary>
/// Calculate penalty value for Third rule.
/// </summary>
internal override int PenaltyCalculate(BitMatrix matrix) => PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
/// <summary>
/// Calculate penalty value for Third rule.
/// </summary>
internal override int PenaltyCalculate(BitMatrix matrix) => PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
{
int i = 0;
int j = 1;
int penalty = 0;
int width = matrix.Width;
bool bit;
while (i < width)
{
while (j < width - 5)
{
bit = isHorizontal
? matrix[j + 4, i]
: matrix[i, j + 4];
if (!bit)
{
bit = isHorizontal
? matrix[j, i]
: matrix[i, j];
if (!bit)
{
penalty += PatternCheck(matrix, i, j, isHorizontal);
j += 4;
}
else
{
j += 4;
}
}
else
{
for (int num = 4; num > 0; num--)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (!bit)
{
j += num;
break;
}
if (num == 1)
{
j += 5;
}
}
}
}
j = 0;
i++;
}
return penalty;
}
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
{
int i = 0;
int j = 1;
int penalty = 0;
int width = matrix.Width;
bool bit;
while (i < width)
{
while (j < width - 5)
{
bit = isHorizontal
? matrix[j + 4, i]
: matrix[i, j + 4];
if (!bit)
{
bit = isHorizontal
? matrix[j, i]
: matrix[i, j];
if (!bit)
{
penalty += PatternCheck(matrix, i, j, isHorizontal);
j += 4;
}
else
{
j += 4;
}
}
else
{
for (int num = 4; num > 0; num--)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (!bit)
{
j += num;
break;
}
if (num == 1)
{
j += 5;
}
}
}
}
j = 0;
i++;
}
return penalty;
}
private int PatternCheck(BitMatrix matrix, int i, int j, bool isHorizontal)
{
bool bit;
for (int num = 3; num >= 1; num--)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (!bit)
{
return 0;
}
}
private int PatternCheck(BitMatrix matrix, int i, int j, bool isHorizontal)
{
bool bit;
for (int num = 3; num >= 1; num--)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (!bit)
{
return 0;
}
}
// Check for left side and right side x ( xoxxxox ).
if ((j - 1) < 0 || (j + 1) >= matrix.Width)
{
return 0;
}
// Check for left side and right side x ( xoxxxox ).
if ((j - 1) < 0 || (j + 1) >= matrix.Width)
{
return 0;
}
bit = isHorizontal
? matrix[j + 5, i]
: matrix[i, j + 5];
if (!bit)
{
return 0;
}
bit = isHorizontal
? matrix[j + 5, i]
: matrix[i, j + 5];
if (!bit)
{
return 0;
}
bit = isHorizontal
? matrix[j - 1, i]
: matrix[i, j - 1];
if (!bit)
{
return 0;
}
bit = isHorizontal
? matrix[j - 1, i]
: matrix[i, j - 1];
if (!bit)
{
return 0;
}
if ((j - 5) >= 0)
{
for (int num = -2; num >= -5; num--)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (bit)
{
break;
}
if ((j - 5) >= 0)
{
for (int num = -2; num >= -5; num--)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (bit)
{
break;
}
if (num == -5)
{
return 40;
}
}
}
if (num == -5)
{
return 40;
}
}
}
if ((j + 9) < matrix.Width)
{
for (int num = 6; num <= 9; num++)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (bit)
{
return 0;
}
}
return 40;
}
else
{
return 0;
}
}
}
if ((j + 9) < matrix.Width)
{
for (int num = 6; num <= 9; num++)
{
bit = isHorizontal
? matrix[j + num, i]
: matrix[i, j + num];
if (bit)
{
return 0;
}
}
return 40;
}
else
{
return 0;
}
}
}
@@ -1,5 +1,3 @@
using System;
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
/// <summary>
@@ -7,30 +5,30 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
/// </summary>
internal class Penalty4 : Penalty
{
/// <summary>
/// Calculate penalty value for Fourth rule.
/// Perform O(n) search for available x modules
/// </summary>
internal override int PenaltyCalculate(BitMatrix matrix)
{
int width = matrix.Width;
int darkBitCount = 0;
/// <summary>
/// Calculate penalty value for Fourth rule.
/// Perform O(n) search for available x modules
/// </summary>
internal override int PenaltyCalculate(BitMatrix matrix)
{
int width = matrix.Width;
int darkBitCount = 0;
for (int j = 0; j < width; j++)
{
for (int i = 0; i < width; i++)
{
if (matrix[i, j])
{
darkBitCount++;
}
}
}
for (int j = 0; j < width; j++)
{
for (int i = 0; i < width; i++)
{
if (matrix[i, j])
{
darkBitCount++;
}
}
}
int matrixCount = width * width;
int matrixCount = width * width;
double ratio = (double)darkBitCount / matrixCount;
double ratio = (double)darkBitCount / matrixCount;
return Math.Abs((int)((ratio * 100) - 50)) / 5 * 10;
}
}
return Math.Abs((int)((ratio * 100) - 50)) / 5 * 10;
}
}
@@ -1,6 +1,3 @@
using System;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
/// <summary>
@@ -8,23 +5,23 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
/// </summary>
internal class PenaltyFactory
{
internal Penalty CreateByRule(PenaltyRules penaltyRule)
{
return penaltyRule switch
{
PenaltyRules.Rule01 => new Penalty1(),
PenaltyRules.Rule02 => new Penalty2(),
PenaltyRules.Rule03 => new Penalty3(),
PenaltyRules.Rule04 => new Penalty4(),
_ => throw new ArgumentException($"Unsupport penalty rule: {penaltyRule}", nameof(penaltyRule))
};
}
internal Penalty CreateByRule(PenaltyRules penaltyRule)
{
return penaltyRule switch
{
PenaltyRules.Rule01 => new Penalty1(),
PenaltyRules.Rule02 => new Penalty2(),
PenaltyRules.Rule03 => new Penalty3(),
PenaltyRules.Rule04 => new Penalty4(),
_ => throw new ArgumentException($"Unsupport penalty rule: {penaltyRule}", nameof(penaltyRule))
};
}
internal IEnumerable<Penalty> AllRules()
{
foreach (PenaltyRules penaltyRule in Enum.GetValues(typeof(PenaltyRules)))
{
yield return CreateByRule(penaltyRule);
}
}
}
internal IEnumerable<Penalty> AllRules()
{
foreach (PenaltyRules penaltyRule in Enum.GetValues(typeof(PenaltyRules)))
{
yield return CreateByRule(penaltyRule);
}
}
}
@@ -2,8 +2,8 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
public enum PenaltyRules
{
Rule01 = 1,
Rule02 = 2,
Rule03 = 3,
Rule04 = 4
}
Rule01 = 1,
Rule02 = 2,
Rule03 = 3,
Rule04 = 4
}