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
@@ -1,127 +1,124 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Gma.QrCodeNet.Encoding;
internal sealed class BitList : IEnumerable<bool>
{
internal BitList()
{
Count = 0;
List = new List<byte>(32);
}
internal BitList()
{
Count = 0;
List = new List<byte>(32);
}
internal BitList(IEnumerable<byte> byteArray)
{
Count = byteArray.Count();
List = byteArray.ToList();
}
internal BitList(IEnumerable<byte> byteArray)
{
Count = byteArray.Count();
List = byteArray.ToList();
}
internal List<byte> List { get; }
internal List<byte> List { get; }
internal int Count { get; private set; }
internal int Count { get; private set; }
internal bool this[int index]
{
get
{
if (index < 0 || index >= Count)
{
throw new ArgumentOutOfRangeException(nameof(index), "Index out of range");
}
internal bool this[int index]
{
get
{
if (index < 0 || index >= Count)
{
throw new ArgumentOutOfRangeException(nameof(index), "Index out of range");
}
int value_Renamed = List[index >> 3] & 0xff;
return ((value_Renamed >> (7 - (index & 0x7))) & 1) == 1;
}
}
int value_Renamed = List[index >> 3] & 0xff;
return ((value_Renamed >> (7 - (index & 0x7))) & 1) == 1;
}
}
public IEnumerator<bool> GetEnumerator()
{
int numBytes = Count >> 3;
int remainder = Count & 0x7;
byte value;
for (int index = 0; index < numBytes; index++)
{
value = List[index];
for (int shiftNum = 7; shiftNum >= 0; shiftNum--)
{
yield return ((value >> shiftNum) & 1) == 1;
}
}
if (remainder > 0)
{
value = List[numBytes];
for (int index = 0; index < remainder; index++)
{
yield return ((value >> (7 - index)) & 1) == 1;
}
}
}
public IEnumerator<bool> GetEnumerator()
{
int numBytes = Count >> 3;
int remainder = Count & 0x7;
byte value;
for (int index = 0; index < numBytes; index++)
{
value = List[index];
for (int shiftNum = 7; shiftNum >= 0; shiftNum--)
{
yield return ((value >> shiftNum) & 1) == 1;
}
}
if (remainder > 0)
{
value = List[numBytes];
for (int index = 0; index < remainder; index++)
{
yield return ((value >> (7 - index)) & 1) == 1;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private int ToBit(bool item)
{
return item ? 1 : 0;
}
private int ToBit(bool item)
{
return item ? 1 : 0;
}
internal void Add(bool item)
{
int numBitsinLastByte = Count & 0x7;
internal void Add(bool item)
{
int numBitsinLastByte = Count & 0x7;
// Add one more byte to List when we have no bits in the last byte.
if (numBitsinLastByte == 0)
{
List.Add(0);
}
// Add one more byte to List when we have no bits in the last byte.
if (numBitsinLastByte == 0)
{
List.Add(0);
}
List[Count >> 3] |= (byte)(ToBit(item) << (7 - numBitsinLastByte));
Count++;
}
List[Count >> 3] |= (byte)(ToBit(item) << (7 - numBitsinLastByte));
Count++;
}
internal void Add(IEnumerable<bool> items)
{
foreach (bool item in items)
{
Add(item);
}
}
internal void Add(IEnumerable<bool> items)
{
foreach (bool item in items)
{
Add(item);
}
}
internal void Add(int value, int bitCount)
{
if (bitCount is < 0 or > 32)
{
throw new ArgumentOutOfRangeException(nameof(bitCount), $"{nameof(bitCount)} must be greater than or equal to 0");
}
internal void Add(int value, int bitCount)
{
if (bitCount is < 0 or > 32)
{
throw new ArgumentOutOfRangeException(nameof(bitCount), $"{nameof(bitCount)} must be greater than or equal to 0");
}
int numBitsLeft = bitCount;
int numBitsLeft = bitCount;
while (numBitsLeft > 0)
{
if ((Count & 0x7) == 0 && numBitsLeft >= 8)
{
// Add one more byte to List.
byte newByte = (byte)((value >> (numBitsLeft - 8)) & 0xFF);
AppendByte(newByte);
numBitsLeft -= 8;
}
else
{
bool bit = ((value >> (numBitsLeft - 1)) & 1) == 1;
Add(bit);
numBitsLeft--;
}
}
}
while (numBitsLeft > 0)
{
if ((Count & 0x7) == 0 && numBitsLeft >= 8)
{
// Add one more byte to List.
byte newByte = (byte)((value >> (numBitsLeft - 8)) & 0xFF);
AppendByte(newByte);
numBitsLeft -= 8;
}
else
{
bool bit = ((value >> (numBitsLeft - 1)) & 1) == 1;
Add(bit);
numBitsLeft--;
}
}
}
private void AppendByte(byte item)
{
List.Add(item);
Count += 8;
}
}
private void AppendByte(byte item)
{
List.Add(item);
Count += 8;
}
}
@@ -2,23 +2,23 @@ namespace Gma.QrCodeNet.Encoding;
public abstract class BitMatrix
{
public abstract int Width { get; }
public abstract int Height { get; }
public abstract bool[,] InternalArray { get; }
public abstract int Width { get; }
public abstract int Height { get; }
public abstract bool[,] InternalArray { get; }
public abstract bool this[int i, int j] { get; set; }
public abstract bool this[int i, int j] { get; set; }
internal void CopyTo(TriStateMatrix target, MatrixRectangle sourceArea, MatrixPoint targetPoint, MatrixStatus mstatus)
{
for (int j = 0; j < sourceArea.Size.Height; j++)
{
for (int i = 0; i < sourceArea.Size.Width; i++)
{
bool value = this[sourceArea.Location.X + i, sourceArea.Location.Y + j];
target[targetPoint.X + i, targetPoint.Y + j, mstatus] = value;
}
}
}
internal void CopyTo(TriStateMatrix target, MatrixRectangle sourceArea, MatrixPoint targetPoint, MatrixStatus mstatus)
{
for (int j = 0; j < sourceArea.Size.Height; j++)
{
for (int i = 0; i < sourceArea.Size.Width; i++)
{
bool value = this[sourceArea.Location.X + i, sourceArea.Location.Y + j];
target[targetPoint.X + i, targetPoint.Y + j, mstatus] = value;
}
}
}
internal void CopyTo(TriStateMatrix target, MatrixPoint targetPoint, MatrixStatus mstatus) => CopyTo(target, new MatrixRectangle(new MatrixPoint(0, 0), new MatrixSize(Width, Height)), targetPoint, mstatus);
}
internal void CopyTo(TriStateMatrix target, MatrixPoint targetPoint, MatrixStatus mstatus) => CopyTo(target, new MatrixRectangle(new MatrixPoint(0, 0), new MatrixSize(Width, Height)), targetPoint, mstatus);
}
@@ -2,30 +2,30 @@ namespace Gma.QrCodeNet.Encoding;
public abstract class BitMatrixBase : BitMatrix
{
protected BitMatrixBase(int width, bool[,] internalArray)
{
Width = width;
InternalArray = internalArray;
}
protected BitMatrixBase(int width, bool[,] internalArray)
{
Width = width;
InternalArray = internalArray;
}
protected BitMatrixBase(bool[,] internalArray)
{
InternalArray = internalArray;
int width = internalArray.GetLength(0);
Width = width;
}
protected BitMatrixBase(bool[,] internalArray)
{
InternalArray = internalArray;
int width = internalArray.GetLength(0);
Width = width;
}
public override bool[,] InternalArray { get; }
public override bool[,] InternalArray { get; }
public override int Width { get; }
public override int Width { get; }
public static bool CanCreate(bool[,] internalArray)
{
if (internalArray is null)
{
return false;
}
public static bool CanCreate(bool[,] internalArray)
{
if (internalArray is null)
{
return false;
}
return internalArray.GetLength(0) == internalArray.GetLength(1);
}
}
return internalArray.GetLength(0) == internalArray.GetLength(1);
}
}
@@ -1,48 +1,46 @@
using System;
namespace Gma.QrCodeNet.Encoding.DataEncodation;
public static class CharCountIndicatorTable
{
/// <remarks>ISO/IEC 18004:2000 Table 3 Page 18</remarks>
public static int[] GetCharCountIndicatorSet()
{
return new int[] { 8, 16, 16 };
}
/// <remarks>ISO/IEC 18004:2000 Table 3 Page 18</remarks>
public static int[] GetCharCountIndicatorSet()
{
return new int[] { 8, 16, 16 };
}
public static int GetBitCountInCharCountIndicator(int version)
{
int[] charCountIndicatorSet = GetCharCountIndicatorSet();
int versionGroup = GetVersionGroup(version);
public static int GetBitCountInCharCountIndicator(int version)
{
int[] charCountIndicatorSet = GetCharCountIndicatorSet();
int versionGroup = GetVersionGroup(version);
return charCountIndicatorSet[versionGroup];
}
return charCountIndicatorSet[versionGroup];
}
/// <summary>
/// Used to define length of the Character Count Indicator <see cref="GetBitCountInCharCountIndicator"/>
/// </summary>
/// <returns>Returns the 0 based index of the row from Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator. </returns>
private static int GetVersionGroup(int version)
{
if (version > 40)
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
else if (version >= 27)
{
return 2;
}
else if (version >= 10)
{
return 1;
}
else if (version > 0)
{
return 0;
}
else
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
}
}
/// <summary>
/// Used to define length of the Character Count Indicator <see cref="GetBitCountInCharCountIndicator"/>
/// </summary>
/// <returns>Returns the 0 based index of the row from Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator. </returns>
private static int GetVersionGroup(int version)
{
if (version > 40)
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
else if (version >= 27)
{
return 2;
}
else if (version >= 10)
{
return 1;
}
else if (version > 0)
{
return 0;
}
else
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
}
}
@@ -1,4 +1,3 @@
using System;
using Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
using Gma.QrCodeNet.Encoding.Terminate;
using Gma.QrCodeNet.Encoding.Versions;
@@ -10,53 +9,53 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
/// Which uses sub functions under several different namespaces</remarks>
internal static class DataEncode
{
internal static EncodationStruct Encode(string content, ErrorCorrectionLevel ecLevel)
{
RecognitionStruct recognitionResult = InputRecognise.Recognise(content);
EncoderBase encoderBase = CreateEncoder(recognitionResult.EncodingName);
internal static EncodationStruct Encode(string content, ErrorCorrectionLevel ecLevel)
{
RecognitionStruct recognitionResult = InputRecognise.Recognise(content);
EncoderBase encoderBase = CreateEncoder(recognitionResult.EncodingName);
BitList encodeContent = encoderBase.GetDataBits(content);
BitList encodeContent = encoderBase.GetDataBits(content);
int encodeContentLength = encodeContent.Count;
int encodeContentLength = encodeContent.Count;
VersionControlStruct vcStruct =
VersionControl.InitialSetup(encodeContentLength, ecLevel, recognitionResult.EncodingName);
VersionControlStruct vcStruct =
VersionControl.InitialSetup(encodeContentLength, ecLevel, recognitionResult.EncodingName);
BitList dataCodewords = new();
BitList dataCodewords = new();
// Eci header
if (vcStruct.IsContainECI && vcStruct.ECIHeader is { })
{
dataCodewords.Add(vcStruct.ECIHeader);
}
// Eci header
if (vcStruct.IsContainECI && vcStruct.ECIHeader is { })
{
dataCodewords.Add(vcStruct.ECIHeader);
}
// Header
dataCodewords.Add(encoderBase.GetModeIndicator());
int numLetter = encodeContentLength >> 3;
dataCodewords.Add(encoderBase.GetCharCountIndicator(numLetter, vcStruct.VersionDetail.Version));
// Header
dataCodewords.Add(encoderBase.GetModeIndicator());
int numLetter = encodeContentLength >> 3;
dataCodewords.Add(encoderBase.GetCharCountIndicator(numLetter, vcStruct.VersionDetail.Version));
// Data
dataCodewords.Add(encodeContent);
// Data
dataCodewords.Add(encodeContent);
// Terminator Padding
dataCodewords.TerminateBites(dataCodewords.Count, vcStruct.VersionDetail.NumDataBytes);
// Terminator Padding
dataCodewords.TerminateBites(dataCodewords.Count, vcStruct.VersionDetail.NumDataBytes);
int dataCodewordsCount = dataCodewords.Count;
if ((dataCodewordsCount & 0x7) != 0)
{
throw new ArgumentException($"{nameof(dataCodewords)} is not byte sized.");
}
else if (dataCodewordsCount >> 3 != vcStruct.VersionDetail.NumDataBytes)
{
throw new ArgumentException($"{nameof(dataCodewords)} num of bytes not equal to {nameof(vcStruct.VersionDetail.NumDataBytes)} for current version");
}
int dataCodewordsCount = dataCodewords.Count;
if ((dataCodewordsCount & 0x7) != 0)
{
throw new ArgumentException($"{nameof(dataCodewords)} is not byte sized.");
}
else if (dataCodewordsCount >> 3 != vcStruct.VersionDetail.NumDataBytes)
{
throw new ArgumentException($"{nameof(dataCodewords)} num of bytes not equal to {nameof(vcStruct.VersionDetail.NumDataBytes)} for current version");
}
var encStruct = new EncodationStruct(vcStruct, dataCodewords);
return encStruct;
}
var encStruct = new EncodationStruct(vcStruct, dataCodewords);
return encStruct;
}
private static EncoderBase CreateEncoder(string encodingName)
{
return new EightBitByteEncoder(encodingName);
}
}
private static EncoderBase CreateEncoder(string encodingName)
{
return new EightBitByteEncoder(encodingName);
}
}
@@ -1,255 +1,252 @@
using System;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.DataEncodation;
public sealed class ECISet
{
/// <summary>
/// ISO/IEC 18004:2006 Chapter 6.4.2 Mode indicator = 0111 Page 23
/// </summary>
private const int ECIMode = 7;
/// <summary>
/// ISO/IEC 18004:2006 Chapter 6.4.2 Mode indicator = 0111 Page 23
/// </summary>
private const int ECIMode = 7;
private const int ECIIndicatorNumBits = 4;
private const int ECIIndicatorNumBits = 4;
private Dictionary<string, int>? _nameToValue;
private Dictionary<int, string>? _valueToName;
private Dictionary<string, int>? _nameToValue;
private Dictionary<int, string>? _valueToName;
/// <summary>
/// Initialize ECI Set.
/// </summary>
/// <param name="option">AppendOption is enum under ECISet
/// Use NameToValue during Encode. ValueToName during Decode</param>
internal ECISet(AppendOption option)
{
Initialize(option);
}
/// <summary>
/// Initialize ECI Set.
/// </summary>
/// <param name="option">AppendOption is enum under ECISet
/// Use NameToValue during Encode. ValueToName during Decode</param>
internal ECISet(AppendOption option)
{
Initialize(option);
}
public enum AppendOption
{
NameToValue,
ValueToName,
Both
}
public enum AppendOption
{
NameToValue,
ValueToName,
Both
}
/// <summary>
/// Length indicator for number of ECI codewords
/// </summary>
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.
/// 1 codeword length = 0. Any additional codeword add 1 to front. Eg: 3 = 110</remarks>
/// <description>Bits required for each one is:
/// one = 1, two = 2, three = 3</description>
private enum ECICodewordsLength
{
One = 0,
Two = 2,
Three = 6
}
/// <summary>
/// Length indicator for number of ECI codewords
/// </summary>
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.
/// 1 codeword length = 0. Any additional codeword add 1 to front. Eg: 3 = 110</remarks>
/// <description>Bits required for each one is:
/// one = 1, two = 2, three = 3</description>
private enum ECICodewordsLength
{
One = 0,
Two = 2,
Three = 6
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of Codewords(Byte) for ECI Assignment Value</returns>
private static int NumOfCodewords(int eCIValue)
{
if (eCIValue is >= 0 and <= 127)
{
return 1;
}
else if (eCIValue is > 127 and <= 16383)
{
return 2;
}
else if (eCIValue is > 16383 and <= 999999)
{
return 3;
}
else
{
throw new ArgumentOutOfRangeException($"{nameof(eCIValue)} should be in range: 0 to 999999.");
}
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of Codewords(Byte) for ECI Assignment Value</returns>
private static int NumOfCodewords(int eCIValue)
{
if (eCIValue is >= 0 and <= 127)
{
return 1;
}
else if (eCIValue is > 127 and <= 16383)
{
return 2;
}
else if (eCIValue is > 16383 and <= 999999)
{
return 3;
}
else
{
throw new ArgumentOutOfRangeException($"{nameof(eCIValue)} should be in range: 0 to 999999.");
}
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Assignment Value</returns>
private static int NumOfAssignmentBits(int eCIValue) => NumOfCodewords(eCIValue) * 8;
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Assignment Value</returns>
private static int NumOfAssignmentBits(int eCIValue) => NumOfCodewords(eCIValue) * 8;
private void AppendECI(string name, int value, AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue?.Add(name, value);
break;
private void AppendECI(string name, int value, AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue?.Add(name, value);
break;
case AppendOption.ValueToName:
_valueToName?.Add(value, name);
break;
case AppendOption.ValueToName:
_valueToName?.Add(value, name);
break;
case AppendOption.Both:
_nameToValue?.Add(name, value);
_valueToName?.Add(value, name);
break;
case AppendOption.Both:
_nameToValue?.Add(name, value);
_valueToName?.Add(value, name);
break;
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
}
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
}
private void Initialize(AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue = new Dictionary<string, int>();
break;
private void Initialize(AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue = new Dictionary<string, int>();
break;
case AppendOption.ValueToName:
_valueToName = new Dictionary<int, string>();
break;
case AppendOption.ValueToName:
_valueToName = new Dictionary<int, string>();
break;
case AppendOption.Both:
_nameToValue = new Dictionary<string, int>();
_valueToName = new Dictionary<int, string>();
break;
case AppendOption.Both:
_nameToValue = new Dictionary<string, int>();
_valueToName = new Dictionary<int, string>();
break;
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
// ECI table. Source 01 URL: http://strokescribe.com/en/ECI.html
// ECI table. Source 02 URL: http://lab.must.or.kr/Extended-Channel-Interpretations-ECI-Encoding.ashx
// ToDo. Fill up remaining missing table.
AppendECI("iso-8859-1", 1, option);
AppendECI("IBM437", 2, option);
// ECI table. Source 01 URL: http://strokescribe.com/en/ECI.html
// ECI table. Source 02 URL: http://lab.must.or.kr/Extended-Channel-Interpretations-ECI-Encoding.ashx
// ToDo. Fill up remaining missing table.
AppendECI("iso-8859-1", 1, option);
AppendECI("IBM437", 2, option);
// AppendECI("iso-8859-1", 3, option); //ECI value 1 is default encoding.
AppendECI("iso-8859-2", 4, option);
AppendECI("iso-8859-3", 5, option);
AppendECI("iso-8859-4", 6, option);
AppendECI("iso-8859-5", 7, option);
AppendECI("iso-8859-6", 8, option);
AppendECI("iso-8859-7", 9, option);
AppendECI("iso-8859-8", 10, option);
AppendECI("iso-8859-9", 11, option);
AppendECI("windows-874", 13, option);
AppendECI("iso-8859-13", 15, option);
AppendECI("iso-8859-15", 17, option);
AppendECI("shift_jis", 20, option);
AppendECI("utf-8", 26, option);
}
// AppendECI("iso-8859-1", 3, option); //ECI value 1 is default encoding.
AppendECI("iso-8859-2", 4, option);
AppendECI("iso-8859-3", 5, option);
AppendECI("iso-8859-4", 6, option);
AppendECI("iso-8859-5", 7, option);
AppendECI("iso-8859-6", 8, option);
AppendECI("iso-8859-7", 9, option);
AppendECI("iso-8859-8", 10, option);
AppendECI("iso-8859-9", 11, option);
AppendECI("windows-874", 13, option);
AppendECI("iso-8859-13", 15, option);
AppendECI("iso-8859-15", 17, option);
AppendECI("shift_jis", 20, option);
AppendECI("utf-8", 26, option);
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Header</returns>
internal static int NumOfECIHeaderBits(int eCIValue) => NumOfAssignmentBits(eCIValue) + 4;
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Header</returns>
internal static int NumOfECIHeaderBits(int eCIValue) => NumOfAssignmentBits(eCIValue) + 4;
internal int GetECIValueByName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
internal int GetECIValueByName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
if (_nameToValue!.TryGetValue(encodingName, out int eCIValue))
{
return eCIValue;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain encoding: {encodingName}.");
}
}
if (_nameToValue!.TryGetValue(encodingName, out int eCIValue))
{
return eCIValue;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain encoding: {encodingName}.");
}
}
internal string GetECINameByValue(int eCIValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
internal string GetECINameByValue(int eCIValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
if (_valueToName!.TryGetValue(eCIValue, out var eCIName))
{
return eCIName;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain value: {eCIValue}.");
}
}
if (_valueToName!.TryGetValue(eCIValue, out var eCIName))
{
return eCIName;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain value: {eCIValue}.");
}
}
/// <returns>ECI table in Dictionary collection</returns>
public Dictionary<string, int>? GetECITable()
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
/// <returns>ECI table in Dictionary collection</returns>
public Dictionary<string, int>? GetECITable()
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
return _nameToValue;
}
return _nameToValue;
}
public bool ContainsECIName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
public bool ContainsECIName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
return _nameToValue!.ContainsKey(encodingName);
}
return _nameToValue!.ContainsKey(encodingName);
}
public bool ContainsECIValue(int eciValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
public bool ContainsECIValue(int eciValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
return _valueToName!.ContainsKey(eciValue);
}
return _valueToName!.ContainsKey(eciValue);
}
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.</remarks>
internal BitList GetECIHeader(string encodingName)
{
int eciValue = GetECIValueByName(encodingName);
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.</remarks>
internal BitList GetECIHeader(string encodingName)
{
int eciValue = GetECIValueByName(encodingName);
BitList dataBits = new()
{
{ ECIMode, ECIIndicatorNumBits }
};
BitList dataBits = new()
{
{ ECIMode, ECIIndicatorNumBits }
};
int eciAssignmentByte = NumOfCodewords(eciValue);
int eciAssignmentByte = NumOfCodewords(eciValue);
// Number of bits = Num codewords indicator + codeword value = Number of codewords * 8
// Chapter 6.4.2.1 ECI Designator ISOIEC 18004:2006 Page 24
int eciAssignmentBits;
switch (eciAssignmentByte)
{
case 1:
// Indicator = 0. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.One, 1);
eciAssignmentBits = (eciAssignmentByte * 8) - 1;
break;
// Number of bits = Num codewords indicator + codeword value = Number of codewords * 8
// Chapter 6.4.2.1 ECI Designator ISOIEC 18004:2006 Page 24
int eciAssignmentBits;
switch (eciAssignmentByte)
{
case 1:
// Indicator = 0. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.One, 1);
eciAssignmentBits = (eciAssignmentByte * 8) - 1;
break;
case 2:
// Indicator = 10. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Two, 2);
eciAssignmentBits = (eciAssignmentByte * 8) - 2;
break;
case 2:
// Indicator = 10. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Two, 2);
eciAssignmentBits = (eciAssignmentByte * 8) - 2;
break;
case 3:
// Indicator = 110. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Three, 3);
eciAssignmentBits = (eciAssignmentByte * 8) - 3;
break;
case 3:
// Indicator = 110. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Three, 3);
eciAssignmentBits = (eciAssignmentByte * 8) - 3;
break;
default:
throw new InvalidOperationException("Assignment Codewords should be either 1, 2 or 3.");
}
default:
throw new InvalidOperationException("Assignment Codewords should be either 1, 2 or 3.");
}
dataBits.Add(eciValue, eciAssignmentBits);
dataBits.Add(eciValue, eciAssignmentBits);
return dataBits;
}
}
return dataBits;
}
}
@@ -1,5 +1,3 @@
using System;
namespace Gma.QrCodeNet.Encoding.DataEncodation;
/// <summary>
@@ -14,67 +12,67 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
/// <remarks>ISO/IEC 18004:2000 Chapter 8.4.4 Page 22</remarks>
internal class EightBitByteEncoder : EncoderBase
{
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
/// <summary>
/// Bitcount, Chapter 8.4.4, P.24
/// </summary>
private const int EightBitByteBitcount = 8;
/// <summary>
/// Bitcount, Chapter 8.4.4, P.24
/// </summary>
private const int EightBitByteBitcount = 8;
/// <summary>
/// EightBitByte encoder's encoding will change according to different region
/// </summary>
/// <param name="encoding">Default encoding is "iso-8859-1"</param>
internal EightBitByteEncoder(string encoding) : base()
{
Encoding = encoding ?? DefaultEncoding;
}
/// <summary>
/// EightBitByte encoder's encoding will change according to different region
/// </summary>
/// <param name="encoding">Default encoding is "iso-8859-1"</param>
internal EightBitByteEncoder(string encoding) : base()
{
Encoding = encoding ?? DefaultEncoding;
}
internal EightBitByteEncoder() : base()
{
Encoding = DefaultEncoding;
}
internal EightBitByteEncoder() : base()
{
Encoding = DefaultEncoding;
}
internal string Encoding { get; private set; }
internal string Encoding { get; private set; }
protected byte[] EncodeContent(string content, string encoding) => System.Text.Encoding.GetEncoding(encoding).GetBytes(content);
protected byte[] EncodeContent(string content, string encoding) => System.Text.Encoding.GetEncoding(encoding).GetBytes(content);
internal override BitList GetDataBits(string content)
{
var eciSet = new ECISet(ECISet.AppendOption.NameToValue);
if (!eciSet.ContainsECIName(Encoding))
{
throw new ArgumentOutOfRangeException(
nameof(Encoding),
$"Current ECI table does not support this encoding. Please check {nameof(ECISet)} class for more info.");
}
internal override BitList GetDataBits(string content)
{
var eciSet = new ECISet(ECISet.AppendOption.NameToValue);
if (!eciSet.ContainsECIName(Encoding))
{
throw new ArgumentOutOfRangeException(
nameof(Encoding),
$"Current ECI table does not support this encoding. Please check {nameof(ECISet)} class for more info.");
}
byte[] contentBytes = EncodeContent(content, Encoding);
byte[] contentBytes = EncodeContent(content, Encoding);
return GetDataBitsByByteArray(contentBytes, Encoding);
}
return GetDataBitsByByteArray(contentBytes, Encoding);
}
internal BitList GetDataBitsByByteArray(byte[] encodeContent, string encodingName)
{
var dataBits = new BitList();
internal BitList GetDataBitsByByteArray(byte[] encodeContent, string encodingName)
{
var dataBits = new BitList();
// Current plan for UTF8 support is put Byte order Mark in front of content byte.
// Also include ECI header before encoding header. Which will be add with encoding header.
if (encodingName == "utf-8")
{
byte[] utf8BOM = QRCodeConstantVariable.UTF8ByteOrderMark;
for (int index = 0; index < utf8BOM.Length; index++)
{
dataBits.Add(utf8BOM[index], EightBitByteBitcount);
}
}
// Current plan for UTF8 support is put Byte order Mark in front of content byte.
// Also include ECI header before encoding header. Which will be add with encoding header.
if (encodingName == "utf-8")
{
byte[] utf8BOM = QRCodeConstantVariable.UTF8ByteOrderMark;
for (int index = 0; index < utf8BOM.Length; index++)
{
dataBits.Add(utf8BOM[index], EightBitByteBitcount);
}
}
for (int index = 0; index < encodeContent.Length; index++)
{
dataBits.Add(encodeContent[index], EightBitByteBitcount);
}
return dataBits;
}
for (int index = 0; index < encodeContent.Length; index++)
{
dataBits.Add(encodeContent[index], EightBitByteBitcount);
}
return dataBits;
}
protected override int GetBitCountInCharCountIndicator(int version) => CharCountIndicatorTable.GetBitCountInCharCountIndicator(version);
}
protected override int GetBitCountInCharCountIndicator(int version) => CharCountIndicatorTable.GetBitCountInCharCountIndicator(version);
}
@@ -4,12 +4,12 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
internal struct EncodationStruct
{
internal EncodationStruct(VersionControlStruct vcStruct, BitList dataCodewords)
{
VersionDetail = vcStruct.VersionDetail;
DataCodewords = dataCodewords;
}
internal EncodationStruct(VersionControlStruct vcStruct, BitList dataCodewords)
{
VersionDetail = vcStruct.VersionDetail;
DataCodewords = dataCodewords;
}
internal VersionDetail VersionDetail { get; set; }
internal BitList DataCodewords { get; set; }
}
internal VersionDetail VersionDetail { get; set; }
internal BitList DataCodewords { get; set; }
}
@@ -2,45 +2,45 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
public abstract class EncoderBase
{
internal EncoderBase()
{
}
internal EncoderBase()
{
}
protected virtual int GetDataLength(string content) => content.Length;
protected virtual int GetDataLength(string content) => content.Length;
/// <summary>
/// Returns the bit representation of input data.
/// </summary>
internal abstract BitList GetDataBits(string content);
/// <summary>
/// Returns the bit representation of input data.
/// </summary>
internal abstract BitList GetDataBits(string content);
/// <summary>
/// Returns bit representation of Modevalue.
/// </summary>
/// <remarks>See Chapter 8.4 Data encodation, Table 2 — Mode indicators</remarks>
internal BitList GetModeIndicator()
{
BitList modeIndicatorBits = new()
{
{ 0001 << 2, 4 }
};
return modeIndicatorBits;
}
/// <summary>
/// Returns bit representation of Modevalue.
/// </summary>
/// <remarks>See Chapter 8.4 Data encodation, Table 2 — Mode indicators</remarks>
internal BitList GetModeIndicator()
{
BitList modeIndicatorBits = new()
{
{ 0001 << 2, 4 }
};
return modeIndicatorBits;
}
internal BitList GetCharCountIndicator(int characterCount, int version)
{
BitList characterCountBits = new();
int bitCount = GetBitCountInCharCountIndicator(version);
characterCountBits.Add(characterCount, bitCount);
return characterCountBits;
}
internal BitList GetCharCountIndicator(int characterCount, int version)
{
BitList characterCountBits = new();
int bitCount = GetBitCountInCharCountIndicator(version);
characterCountBits.Add(characterCount, bitCount);
return characterCountBits;
}
/// <summary>
/// Defines the length of the Character Count Indicator,
/// which varies according to the mode and the symbol version in use
/// </summary>
/// <returns>Number of bits in Character Count Indicator.</returns>
/// <remarks>
/// See Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator.
/// </remarks>
protected abstract int GetBitCountInCharCountIndicator(int version);
}
/// <summary>
/// Defines the length of the Character Count Indicator,
/// which varies according to the mode and the symbol version in use
/// </summary>
/// <returns>Number of bits in Character Count Indicator.</returns>
/// <remarks>
/// See Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator.
/// </remarks>
protected abstract int GetBitCountInCharCountIndicator(int version);
}
@@ -1,57 +1,54 @@
using System;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
public static class InputRecognise
{
public static RecognitionStruct Recognise(string content)
{
string encodingName = EightBitByteRecognision(content, 0, content.Length);
return new RecognitionStruct(encodingName);
}
public static RecognitionStruct Recognise(string content)
{
string encodingName = EightBitByteRecognision(content, 0, content.Length);
return new RecognitionStruct(encodingName);
}
private static string EightBitByteRecognision(string content, int startPos, int contentLength)
{
if(string.IsNullOrEmpty(content))
private static string EightBitByteRecognision(string content, int startPos, int contentLength)
{
if (string.IsNullOrEmpty(content))
throw new ArgumentNullException(nameof(content));
var eciSets = new ECISet(ECISet.AppendOption.NameToValue);
var eciSets = new ECISet(ECISet.AppendOption.NameToValue);
Dictionary<string, int>? eciSet = eciSets.GetECITable();
Dictionary<string, int>? eciSet = eciSets.GetECITable();
if(eciSet == null)
if (eciSet == null)
return string.Empty;
// we will not check for utf8 encoding.
eciSet.Remove(QRCodeConstantVariable.UTF8Encoding);
eciSet.Remove(QRCodeConstantVariable.DefaultEncoding);
// we will not check for utf8 encoding.
eciSet.Remove(QRCodeConstantVariable.UTF8Encoding);
eciSet.Remove(QRCodeConstantVariable.DefaultEncoding);
int scanPos = startPos;
int scanPos = startPos;
// default encoding as priority
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, QRCodeConstantVariable.DefaultEncoding, scanPos, contentLength);
if (scanPos == -1)
{
return QRCodeConstantVariable.DefaultEncoding;
}
// default encoding as priority
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, QRCodeConstantVariable.DefaultEncoding, scanPos, contentLength);
if (scanPos == -1)
{
return QRCodeConstantVariable.DefaultEncoding;
}
foreach (KeyValuePair<string, int> kvp in eciSet)
{
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, kvp.Key, scanPos, contentLength);
if (scanPos == -1)
{
return kvp.Key;
}
}
foreach (KeyValuePair<string, int> kvp in eciSet)
{
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, kvp.Key, scanPos, contentLength);
if (scanPos == -1)
{
return kvp.Key;
}
}
if (scanPos == -1)
{
throw new ArgumentException("foreach Loop check give wrong result.");
}
else
{
return QRCodeConstantVariable.UTF8Encoding;
}
}
}
if (scanPos == -1)
{
throw new ArgumentException("foreach Loop check give wrong result.");
}
else
{
return QRCodeConstantVariable.UTF8Encoding;
}
}
}
@@ -1,72 +1,70 @@
using System;
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
public static class ModeEncodeCheck
{
/// <summary>
/// Encoding.GetEncoding.GetBytes will transform char to 0x3F if that char not belong to current encoding table.
/// 0x3F is '?'
/// </summary>
private const int QuestionMarkChar = 0x3F;
/// <summary>
/// Encoding.GetEncoding.GetBytes will transform char to 0x3F if that char not belong to current encoding table.
/// 0x3F is '?'
/// </summary>
private const int QuestionMarkChar = 0x3F;
/// <summary>
/// Use given encoding to check input string from starting position. If encoding table is suitable solution.
/// it will return -1. Else it will return failed encoding position.
/// </summary>
/// <param name="content">Input string</param>
/// <param name="encodingName">Encoding name. Check ECI table</param>
/// <returns>Returns -1 if from starting position to end encoding success. Else returns fail position</returns>
internal static int TryEncodeEightBitByte(string content, string encodingName, int startingPosition, int contentLength)
{
if (string.IsNullOrEmpty(content))
{
throw new IndexOutOfRangeException("Input cannot be null or empty.");
}
/// <summary>
/// Use given encoding to check input string from starting position. If encoding table is suitable solution.
/// it will return -1. Else it will return failed encoding position.
/// </summary>
/// <param name="content">Input string</param>
/// <param name="encodingName">Encoding name. Check ECI table</param>
/// <returns>Returns -1 if from starting position to end encoding success. Else returns fail position</returns>
internal static int TryEncodeEightBitByte(string content, string encodingName, int startingPosition, int contentLength)
{
if (string.IsNullOrEmpty(content))
{
throw new IndexOutOfRangeException("Input cannot be null or empty.");
}
System.Text.Encoding encoding;
try
{
encoding = System.Text.Encoding.GetEncoding(encodingName);
}
catch (ArgumentException)
{
return startingPosition;
}
System.Text.Encoding encoding;
try
{
encoding = System.Text.Encoding.GetEncoding(encodingName);
}
catch (ArgumentException)
{
return startingPosition;
}
char[] currentChar = new char[1];
byte[] bytes;
char[] currentChar = new char[1];
byte[] bytes;
for (int index = startingPosition; index < contentLength; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
for (int index = startingPosition; index < contentLength; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
for (int index = 0; index < startingPosition; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
for (int index = 0; index < startingPosition; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
return -1;
}
}
return -1;
}
}
@@ -2,11 +2,11 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
public struct RecognitionStruct
{
public RecognitionStruct(string encodingName)
: this()
{
EncodingName = encodingName;
}
public RecognitionStruct(string encodingName)
: this()
{
EncodingName = encodingName;
}
public string EncodingName { get; private set; }
}
public string EncodingName { get; private set; }
}
@@ -2,59 +2,59 @@ namespace Gma.QrCodeNet.Encoding.EncodingRegion;
internal static class BCHCalculator
{
/// <summary>
/// Calculate int length by search for Most significant bit
/// </summary>
/// <param name="num">Input Number</param>
/// <returns>Most significant bit</returns>
internal static int PosMSB(int num) => num == 0 ? 0 : BinarySearchPos(num, 0, 32) + 1;
/// <summary>
/// Calculate int length by search for Most significant bit
/// </summary>
/// <param name="num">Input Number</param>
/// <returns>Most significant bit</returns>
internal static int PosMSB(int num) => num == 0 ? 0 : BinarySearchPos(num, 0, 32) + 1;
/// <summary>
/// Search for right side bit of Most significant bit
/// </summary>
/// <param name="num">Input number</param>
/// <param name="lowBoundary">Lower boundary. At start should be 0</param>
/// <param name="highBoundary">Higher boundary. At start should be 32</param>
/// <returns>Most significant bit - 1</returns>
private static int BinarySearchPos(int num, int lowBoundary, int highBoundary)
{
int mid = (lowBoundary + highBoundary) / 2;
int shiftResult = num >> mid;
if (shiftResult == 1)
{
return mid;
}
else if (shiftResult < 1)
{
return BinarySearchPos(num, lowBoundary, mid);
}
else
{
return BinarySearchPos(num, mid, highBoundary);
}
}
/// <summary>
/// Search for right side bit of Most significant bit
/// </summary>
/// <param name="num">Input number</param>
/// <param name="lowBoundary">Lower boundary. At start should be 0</param>
/// <param name="highBoundary">Higher boundary. At start should be 32</param>
/// <returns>Most significant bit - 1</returns>
private static int BinarySearchPos(int num, int lowBoundary, int highBoundary)
{
int mid = (lowBoundary + highBoundary) / 2;
int shiftResult = num >> mid;
if (shiftResult == 1)
{
return mid;
}
else if (shiftResult < 1)
{
return BinarySearchPos(num, lowBoundary, mid);
}
else
{
return BinarySearchPos(num, mid, highBoundary);
}
}
/// <summary>
/// With input number and polynomial number. Method will calculate BCH value and return
/// </summary>
/// <param name="num">Input number</param>
/// <param name="poly">Polynomial number</param>
/// <returns>BCH value</returns>
internal static int CalculateBCH(int num, int poly)
{
int polyMSB = PosMSB(poly);
/// <summary>
/// With input number and polynomial number. Method will calculate BCH value and return
/// </summary>
/// <param name="num">Input number</param>
/// <param name="poly">Polynomial number</param>
/// <returns>BCH value</returns>
internal static int CalculateBCH(int num, int poly)
{
int polyMSB = PosMSB(poly);
// num's length will be old length + new length - 1.
// Once divide poly number. BCH number will be one length short than Poly number's length.
num <<= (polyMSB - 1);
int numMSB = PosMSB(num);
while (PosMSB(num) >= polyMSB)
{
// left shift Poly number to same level as num. Then xor.
// Remove most significant bits of num.
num ^= poly << (numMSB - polyMSB);
numMSB = PosMSB(num);
}
return num;
}
}
// num's length will be old length + new length - 1.
// Once divide poly number. BCH number will be one length short than Poly number's length.
num <<= (polyMSB - 1);
int numMSB = PosMSB(num);
while (PosMSB(num) >= polyMSB)
{
// left shift Poly number to same level as num. Then xor.
// Remove most significant bits of num.
num ^= poly << (numMSB - polyMSB);
numMSB = PosMSB(num);
}
return num;
}
}
@@ -1,72 +1,70 @@
using System;
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
/// <remarks>ISO/IEC 18004:2000 Chapter 8.7.3 Page 46</remarks>
internal static class Codeword
{
internal static void TryEmbedCodewords(this TriStateMatrix tsMatrix, BitList codewords)
{
int sWidth = tsMatrix.Width;
int codewordsSize = codewords.Count;
internal static void TryEmbedCodewords(this TriStateMatrix tsMatrix, BitList codewords)
{
int sWidth = tsMatrix.Width;
int codewordsSize = codewords.Count;
int bitIndex = 0;
int directionUp = -1;
int bitIndex = 0;
int directionUp = -1;
int x = sWidth - 1;
int y = sWidth - 1;
int x = sWidth - 1;
int y = sWidth - 1;
while (x > 0)
{
// Skip vertical timing pattern
if (x == 6)
{
x -= 1;
}
while (x > 0)
{
// Skip vertical timing pattern
if (x == 6)
{
x -= 1;
}
while (y >= 0 && y < sWidth)
{
for (int xOffset = 0; xOffset < 2; xOffset++)
{
int xPos = x - xOffset;
if (tsMatrix.MStatus(xPos, y) == MatrixStatus.None)
{
bool bit;
if (bitIndex < codewordsSize)
{
bit = codewords[bitIndex];
bitIndex++;
}
else
{
bit = false;
}
while (y >= 0 && y < sWidth)
{
for (int xOffset = 0; xOffset < 2; xOffset++)
{
int xPos = x - xOffset;
if (tsMatrix.MStatus(xPos, y) == MatrixStatus.None)
{
bool bit;
if (bitIndex < codewordsSize)
{
bit = codewords[bitIndex];
bitIndex++;
}
else
{
bit = false;
}
tsMatrix[xPos, y, MatrixStatus.Data] = bit;
}
}
tsMatrix[xPos, y, MatrixStatus.Data] = bit;
}
}
y = NextY(y, directionUp);
}
y = NextY(y, directionUp);
}
directionUp = ChangeDirection(directionUp);
y = NextY(y, directionUp);
x -= 2;
}
directionUp = ChangeDirection(directionUp);
y = NextY(y, directionUp);
x -= 2;
}
if (bitIndex != codewordsSize)
{
throw new Exception($"Not all bits from {nameof(codewords)} consumed by matrix: {bitIndex} / {codewordsSize}.");
}
}
if (bitIndex != codewordsSize)
{
throw new Exception($"Not all bits from {nameof(codewords)} consumed by matrix: {bitIndex} / {codewordsSize}.");
}
}
internal static int NextY(int y, int directionUp)
{
return y + directionUp;
}
internal static int NextY(int y, int directionUp)
{
return y + directionUp;
}
internal static int ChangeDirection(int directionUp)
{
return -directionUp;
}
}
internal static int ChangeDirection(int directionUp)
{
return -directionUp;
}
}
@@ -1,4 +1,3 @@
using System;
using Gma.QrCodeNet.Encoding.Masking;
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
@@ -10,105 +9,105 @@ namespace Gma.QrCodeNet.Encoding.EncodingRegion;
/// <remarks>ISO/IEC 18004:2000 Chapter 8.9 Page 53</remarks>
internal static class FormatInformation
{
/// <summary>
/// From Appendix C in JISX0510:2004 (p.65).
/// </summary>
private const int FormatInfoPoly = 0x537;
/// <summary>
/// From Appendix C in JISX0510:2004 (p.65).
/// </summary>
private const int FormatInfoPoly = 0x537;
/// <summary>
/// From Appendix C in JISX0510:2004 (p.65).
/// </summary>
private const int FormatInfoMaskPattern = 0x5412;
/// <summary>
/// From Appendix C in JISX0510:2004 (p.65).
/// </summary>
private const int FormatInfoMaskPattern = 0x5412;
/// <summary>
/// Embed format information to tristatematrix.
/// Process combination of create info bits, BCH error correction bits calculation, embed towards matrix.
/// </summary>
/// <remarks>ISO/IEC 18004:2000 Chapter 8.9 Page 53</remarks>
internal static void EmbedFormatInformation(this TriStateMatrix triMatrix, ErrorCorrectionLevel errorLevel, Pattern pattern)
{
BitList formatInfo = GetFormatInfoBits(errorLevel, pattern);
int width = triMatrix.Width;
for (int index = 0; index < 15; index++)
{
MatrixPoint point = PointForInfo1(index);
bool bit = formatInfo[index];
triMatrix[point.X, point.Y, MatrixStatus.NoMask] = bit;
/// <summary>
/// Embed format information to tristatematrix.
/// Process combination of create info bits, BCH error correction bits calculation, embed towards matrix.
/// </summary>
/// <remarks>ISO/IEC 18004:2000 Chapter 8.9 Page 53</remarks>
internal static void EmbedFormatInformation(this TriStateMatrix triMatrix, ErrorCorrectionLevel errorLevel, Pattern pattern)
{
BitList formatInfo = GetFormatInfoBits(errorLevel, pattern);
int width = triMatrix.Width;
for (int index = 0; index < 15; index++)
{
MatrixPoint point = PointForInfo1(index);
bool bit = formatInfo[index];
triMatrix[point.X, point.Y, MatrixStatus.NoMask] = bit;
if (index < 7)
{
triMatrix[8, width - 1 - index, MatrixStatus.NoMask] = bit;
}
else
{
triMatrix[width - 8 + (index - 7), 8, MatrixStatus.NoMask] = bit;
}
}
}
if (index < 7)
{
triMatrix[8, width - 1 - index, MatrixStatus.NoMask] = bit;
}
else
{
triMatrix[width - 8 + (index - 7), 8, MatrixStatus.NoMask] = bit;
}
}
}
private static MatrixPoint PointForInfo1(int bitsIndex)
{
if (bitsIndex <= 7)
{
return bitsIndex >= 6
? new MatrixPoint(bitsIndex + 1, 8)
: new MatrixPoint(bitsIndex, 8);
}
else
{
return bitsIndex == 8
? new MatrixPoint(8, 8 - (bitsIndex - 7))
: new MatrixPoint(8, 8 - (bitsIndex - 7) - 1);
}
}
private static MatrixPoint PointForInfo1(int bitsIndex)
{
if (bitsIndex <= 7)
{
return bitsIndex >= 6
? new MatrixPoint(bitsIndex + 1, 8)
: new MatrixPoint(bitsIndex, 8);
}
else
{
return bitsIndex == 8
? new MatrixPoint(8, 8 - (bitsIndex - 7))
: new MatrixPoint(8, 8 - (bitsIndex - 7) - 1);
}
}
private static BitList GetFormatInfoBits(ErrorCorrectionLevel errorLevel, Pattern pattern)
{
int formatInfo = (int)pattern.MaskPatternType;
private static BitList GetFormatInfoBits(ErrorCorrectionLevel errorLevel, Pattern pattern)
{
int formatInfo = (int)pattern.MaskPatternType;
// Pattern bits length = 3
formatInfo |= GetErrorCorrectionIndicatorBits(errorLevel) << 3;
// Pattern bits length = 3
formatInfo |= GetErrorCorrectionIndicatorBits(errorLevel) << 3;
int bchCode = BCHCalculator.CalculateBCH(formatInfo, FormatInfoPoly);
int bchCode = BCHCalculator.CalculateBCH(formatInfo, FormatInfoPoly);
// bchCode length = 10
formatInfo = (formatInfo << 10) | bchCode;
// bchCode length = 10
formatInfo = (formatInfo << 10) | bchCode;
// xor maskPattern
formatInfo ^= FormatInfoMaskPattern;
// xor maskPattern
formatInfo ^= FormatInfoMaskPattern;
BitList resultBits = new()
{
{ formatInfo, 15 }
};
BitList resultBits = new()
{
{ formatInfo, 15 }
};
if (resultBits.Count != 15)
{
throw new Exception("FormatInfoBits length is not 15");
}
else
{
return resultBits;
}
}
if (resultBits.Count != 15)
{
throw new Exception("FormatInfoBits length is not 15");
}
else
{
return resultBits;
}
}
/// <summary>
/// According Table 25 — Error correction level indicators
/// Using these bits as enum values would destroy their order which currently corresponds to error correction strength.
/// </summary>
internal static int GetErrorCorrectionIndicatorBits(ErrorCorrectionLevel errorLevel)
{
// L 01
// M 00
// Q 11
// H 10
return errorLevel switch
{
ErrorCorrectionLevel.H => 0x02,
ErrorCorrectionLevel.L => 0x01,
ErrorCorrectionLevel.M => 0x00,
ErrorCorrectionLevel.Q => 0x03,
_ => throw new ArgumentException($"Unsupported error correction level [{errorLevel}]", nameof(errorLevel))
};
}
}
/// <summary>
/// According Table 25 — Error correction level indicators
/// Using these bits as enum values would destroy their order which currently corresponds to error correction strength.
/// </summary>
internal static int GetErrorCorrectionIndicatorBits(ErrorCorrectionLevel errorLevel)
{
// L 01
// M 00
// Q 11
// H 10
return errorLevel switch
{
ErrorCorrectionLevel.H => 0x02,
ErrorCorrectionLevel.L => 0x01,
ErrorCorrectionLevel.M => 0x00,
ErrorCorrectionLevel.Q => 0x03,
_ => throw new ArgumentException($"Unsupported error correction level [{errorLevel}]", nameof(errorLevel))
};
}
}
@@ -1,5 +1,3 @@
using System;
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
/// <summary>
@@ -8,63 +6,63 @@ namespace Gma.QrCodeNet.Encoding.EncodingRegion;
/// <remarks>ISO/IEC 18004:2000 Chapter 8.10 Page 54</remarks>
internal static class VersionInformation
{
private const int VIRectangleHeight = 3;
private const int VIRectangleWidth = 6;
private const int VIRectangleHeight = 3;
private const int VIRectangleWidth = 6;
private const int LengthDataBits = 6;
private const int LengthECBits = 12;
private const int VersionBCHPoly = 0x1f25;
private const int LengthDataBits = 6;
private const int LengthECBits = 12;
private const int VersionBCHPoly = 0x1f25;
/// <summary>
/// Embed version information to Matrix
/// Only for version greater than or equal to 7
/// </summary>
internal static void EmbedVersionInformation(this TriStateMatrix tsMatrix, int version)
{
if (version < 7)
{
return;
}
/// <summary>
/// Embed version information to Matrix
/// Only for version greater than or equal to 7
/// </summary>
internal static void EmbedVersionInformation(this TriStateMatrix tsMatrix, int version)
{
if (version < 7)
{
return;
}
BitList versionInfo = VersionInfoBitList(version);
BitList versionInfo = VersionInfoBitList(version);
int matrixWidth = tsMatrix.Width;
int matrixWidth = tsMatrix.Width;
// 1 cell between version info and position stencil
int shiftLength = QRCodeConstantVariable.PositionStencilWidth + VIRectangleHeight + 1;
// 1 cell between version info and position stencil
int shiftLength = QRCodeConstantVariable.PositionStencilWidth + VIRectangleHeight + 1;
// Reverse order input
int viIndex = LengthDataBits + LengthECBits - 1;
// Reverse order input
int viIndex = LengthDataBits + LengthECBits - 1;
for (int viWidth = 0; viWidth < VIRectangleWidth; viWidth++)
{
for (int viHeight = 0; viHeight < VIRectangleHeight; viHeight++)
{
bool bit = versionInfo[viIndex];
viIndex--;
for (int viWidth = 0; viWidth < VIRectangleWidth; viWidth++)
{
for (int viHeight = 0; viHeight < VIRectangleHeight; viHeight++)
{
bool bit = versionInfo[viIndex];
viIndex--;
// Bottom left
tsMatrix[viWidth, (matrixWidth - shiftLength + viHeight), MatrixStatus.NoMask] = bit;
// Bottom left
tsMatrix[viWidth, (matrixWidth - shiftLength + viHeight), MatrixStatus.NoMask] = bit;
// Top right
tsMatrix[(matrixWidth - shiftLength + viHeight), viWidth, MatrixStatus.NoMask] = bit;
}
}
}
// Top right
tsMatrix[(matrixWidth - shiftLength + viHeight), viWidth, MatrixStatus.NoMask] = bit;
}
}
}
private static BitList VersionInfoBitList(int version)
{
BitList result = new()
{
{ version, LengthDataBits },
{ BCHCalculator.CalculateBCH(version, VersionBCHPoly), LengthECBits }
};
private static BitList VersionInfoBitList(int version)
{
BitList result = new()
{
{ version, LengthDataBits },
{ BCHCalculator.CalculateBCH(version, VersionBCHPoly), LengthECBits }
};
if (result.Count != (LengthECBits + LengthDataBits))
{
throw new Exception("Version Info creation error. Result is not 18 bits");
}
if (result.Count != (LengthECBits + LengthDataBits))
{
throw new Exception("Version Info creation error. Result is not 18 bits");
}
return result;
}
}
return result;
}
}
@@ -1,84 +1,82 @@
using Gma.QrCodeNet.Encoding.ReedSolomon;
using System;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.ErrorCorrection;
internal static class ECGenerator
{
internal static BitList FillECCodewords(BitList dataCodewords, VersionDetail vd)
{
List<byte> dataCodewordsByte = dataCodewords.List;
internal static BitList FillECCodewords(BitList dataCodewords, VersionDetail vd)
{
List<byte> dataCodewordsByte = dataCodewords.List;
int ecBlockGroup1 = vd.ECBlockGroup1;
int numDataBytesGroup1 = vd.NumDataBytesGroup1;
int numDataBytesGroup2 = vd.NumDataBytesGroup2;
int ecBlockGroup1 = vd.ECBlockGroup1;
int numDataBytesGroup1 = vd.NumDataBytesGroup1;
int numDataBytesGroup2 = vd.NumDataBytesGroup2;
int ecBytesPerBlock = vd.NumECBytesPerBlock;
int ecBytesPerBlock = vd.NumECBytesPerBlock;
int dataBytesOffset = 0;
byte[][] dByteJArray = new byte[vd.NumECBlocks][];
byte[][] ecByteJArray = new byte[vd.NumECBlocks][];
int dataBytesOffset = 0;
byte[][] dByteJArray = new byte[vd.NumECBlocks][];
byte[][] ecByteJArray = new byte[vd.NumECBlocks][];
GaloisField256 gf256 = GaloisField256.QRCodeGaloisField;
GeneratorPolynomial generator = new(gf256);
GaloisField256 gf256 = GaloisField256.QRCodeGaloisField;
GeneratorPolynomial generator = new(gf256);
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
{
if (blockId < ecBlockGroup1)
{
dByteJArray[blockId] = new byte[numDataBytesGroup1];
for (int index = 0; index < numDataBytesGroup1; index++)
{
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
}
dataBytesOffset += numDataBytesGroup1;
}
else
{
dByteJArray[blockId] = new byte[numDataBytesGroup2];
for (int index = 0; index < numDataBytesGroup2; index++)
{
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
}
dataBytesOffset += numDataBytesGroup2;
}
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
{
if (blockId < ecBlockGroup1)
{
dByteJArray[blockId] = new byte[numDataBytesGroup1];
for (int index = 0; index < numDataBytesGroup1; index++)
{
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
}
dataBytesOffset += numDataBytesGroup1;
}
else
{
dByteJArray[blockId] = new byte[numDataBytesGroup2];
for (int index = 0; index < numDataBytesGroup2; index++)
{
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
}
dataBytesOffset += numDataBytesGroup2;
}
ecByteJArray[blockId] = ReedSolomonEncoder.Encode(dByteJArray[blockId], ecBytesPerBlock, generator);
}
if (vd.NumDataBytes != dataBytesOffset)
{
throw new ArgumentException("Data bytes do not match offset");
}
ecByteJArray[blockId] = ReedSolomonEncoder.Encode(dByteJArray[blockId], ecBytesPerBlock, generator);
}
if (vd.NumDataBytes != dataBytesOffset)
{
throw new ArgumentException("Data bytes do not match offset");
}
BitList codewords = new();
BitList codewords = new();
int maxDataLength = ecBlockGroup1 == vd.NumECBlocks ? numDataBytesGroup1 : numDataBytesGroup2;
int maxDataLength = ecBlockGroup1 == vd.NumECBlocks ? numDataBytesGroup1 : numDataBytesGroup2;
for (int dataId = 0; dataId < maxDataLength; dataId++)
{
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
{
if (!(dataId == numDataBytesGroup1 && blockId < ecBlockGroup1))
{
codewords.Add(dByteJArray[blockId][dataId], 8);
}
}
}
for (int dataId = 0; dataId < maxDataLength; dataId++)
{
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
{
if (!(dataId == numDataBytesGroup1 && blockId < ecBlockGroup1))
{
codewords.Add(dByteJArray[blockId][dataId], 8);
}
}
}
for (int ecId = 0; ecId < ecBytesPerBlock; ecId++)
{
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
{
codewords.Add(ecByteJArray[blockId][ecId], 8);
}
}
for (int ecId = 0; ecId < ecBytesPerBlock; ecId++)
{
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
{
codewords.Add(ecByteJArray[blockId][ecId], 8);
}
}
if (vd.NumTotalBytes != codewords.Count >> 3)
{
throw new ArgumentException($"Total bytes: {vd.NumTotalBytes}. Actual bits: {codewords.Count}");
}
if (vd.NumTotalBytes != codewords.Count >> 3)
{
throw new ArgumentException($"Total bytes: {vd.NumTotalBytes}. Actual bits: {codewords.Count}");
}
return codewords;
}
}
return codewords;
}
}
@@ -2,8 +2,8 @@ namespace Gma.QrCodeNet.Encoding;
public enum ErrorCorrectionLevel
{
L,
M,
Q,
H
}
L,
M,
Q,
H
}
@@ -1,5 +1,3 @@
using System;
namespace Gma.QrCodeNet.Encoding;
/// <summary>
@@ -7,11 +5,11 @@ namespace Gma.QrCodeNet.Encoding;
/// </summary>
public class InputOutOfBoundaryException : Exception
{
public InputOutOfBoundaryException() : base()
{
}
public InputOutOfBoundaryException() : base()
{
}
public InputOutOfBoundaryException(string message) : base(message)
{
}
}
public InputOutOfBoundaryException(string message) : base(message)
{
}
}
@@ -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
}
@@ -2,19 +2,19 @@ namespace Gma.QrCodeNet.Encoding;
public struct MatrixPoint
{
internal MatrixPoint(int x, int y)
: this()
{
X = x;
Y = y;
}
internal MatrixPoint(int x, int y)
: this()
{
X = x;
Y = y;
}
public int X { get; private set; }
public int Y { get; private set; }
public int X { get; private set; }
public int Y { get; private set; }
public MatrixPoint Offset(MatrixPoint offset) => new(offset.X + X, offset.Y + Y);
public MatrixPoint Offset(MatrixPoint offset) => new(offset.X + X, offset.Y + Y);
internal MatrixPoint Offset(int offsetX, int offsetY) => Offset(new MatrixPoint(offsetX, offsetY));
internal MatrixPoint Offset(int offsetX, int offsetY) => Offset(new MatrixPoint(offsetX, offsetY));
public override string ToString() => $"Point({X};{Y})";
}
public override string ToString() => $"Point({X};{Y})";
}
@@ -1,32 +1,31 @@
using System.Collections;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding;
internal struct MatrixRectangle : IEnumerable<MatrixPoint>
{
internal MatrixRectangle(MatrixPoint location, MatrixSize size) :
this()
{
Location = location;
Size = size;
}
internal MatrixRectangle(MatrixPoint location, MatrixSize size) :
this()
{
Location = location;
Size = size;
}
public MatrixPoint Location { get; private set; }
public MatrixSize Size { get; private set; }
public MatrixPoint Location { get; private set; }
public MatrixSize Size { get; private set; }
public IEnumerator<MatrixPoint> GetEnumerator()
{
for (int j = Location.Y; j < Location.Y + Size.Height; j++)
{
for (int i = Location.X; i < Location.X + Size.Width; i++)
{
yield return new MatrixPoint(i, j);
}
}
}
public IEnumerator<MatrixPoint> GetEnumerator()
{
for (int j = Location.Y; j < Location.Y + Size.Height; j++)
{
for (int i = Location.X; i < Location.X + Size.Width; i++)
{
yield return new MatrixPoint(i, j);
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public override string ToString() => $"Rectangle({Location.X};{Location.Y}):({Size.Width} x {Size.Height})";
}
public override string ToString() => $"Rectangle({Location.X};{Location.Y}):({Size.Width} x {Size.Height})";
}
@@ -2,18 +2,18 @@ namespace Gma.QrCodeNet.Encoding;
public struct MatrixSize
{
internal MatrixSize(int width, int height)
: this()
{
Width = width;
Height = height;
}
internal MatrixSize(int width, int height)
: this()
{
Width = width;
Height = height;
}
public int Width { get; private set; }
public int Height { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public override string ToString()
{
return $"Size({Width};{Height})";
}
}
public override string ToString()
{
return $"Size({Width};{Height})";
}
}
@@ -2,7 +2,7 @@ namespace Gma.QrCodeNet.Encoding;
public enum MatrixStatus
{
None,
NoMask,
Data
}
None,
NoMask,
Data
}
@@ -4,11 +4,11 @@ namespace Gma.QrCodeNet.Encoding.Positioning;
internal static class PositioningPatternBuilder
{
internal static void EmbedBasicPatterns(int version, TriStateMatrix matrix)
{
new PositionDetectionPattern(version).ApplyTo(matrix);
new DarkDotAtLeftBottom(version).ApplyTo(matrix);
new AlignmentPattern(version).ApplyTo(matrix);
new TimingPattern(version).ApplyTo(matrix);
}
}
internal static void EmbedBasicPatterns(int version, TriStateMatrix matrix)
{
new PositionDetectionPattern(version).ApplyTo(matrix);
new DarkDotAtLeftBottom(version).ApplyTo(matrix);
new AlignmentPattern(version).ApplyTo(matrix);
new TimingPattern(version).ApplyTo(matrix);
}
}
@@ -1,105 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
internal class AlignmentPattern : PatternStencilBase
{
public AlignmentPattern(int version)
: base(version)
{
}
public AlignmentPattern(int version)
: base(version)
{
}
private static bool[,] AlignmentPatternArray { get; } =
new[,]
{
{ X, X, X, X, X },
{ X, O, O, O, X },
{ X, O, X, O, X },
{ X, O, O, O, X },
{ X, X, X, X, X }
};
private static bool[,] AlignmentPatternArray { get; } =
new[,]
{
{ X, X, X, X, X },
{ X, O, O, O, X },
{ X, O, X, O, X },
{ X, O, O, O, X },
{ X, X, X, X, X }
};
public override bool[,] Stencil => AlignmentPatternArray;
public override bool[,] Stencil => AlignmentPatternArray;
// Table E.1 — Row/column coordinates of center module of Alignment Patterns
private static byte[][] AlignmentPatternCoordinatesByVersion { get; } =
new[]
{
Array.Empty<byte>(),
Array.Empty<byte>(),
new byte[] { 6, 18 },
new byte[] { 6, 22 },
new byte[] { 6, 26 },
new byte[] { 6, 30 },
new byte[] { 6, 34 },
new byte[] { 6, 22, 38 },
new byte[] { 6, 24, 42 },
new byte[] { 6, 26, 46 },
new byte[] { 6, 28, 50 },
new byte[] { 6, 30, 54 },
new byte[] { 6, 32, 58 },
new byte[] { 6, 34, 62 },
new byte[] { 6, 26, 46, 66 },
new byte[] { 6, 26, 48, 70 },
new byte[] { 6, 26, 50, 74 },
new byte[] { 6, 30, 54, 78 },
new byte[] { 6, 30, 56, 82 },
new byte[] { 6, 30, 58, 86 },
new byte[] { 6, 34, 62, 90 },
new byte[] { 6, 28, 50, 72, 94 },
new byte[] { 6, 26, 50, 74, 98 },
new byte[] { 6, 30, 54, 78, 102 },
new byte[] { 6, 28, 54, 80, 106 },
new byte[] { 6, 32, 58, 84, 110 },
new byte[] { 6, 30, 58, 86, 114 },
new byte[] { 6, 34, 62, 90, 118 },
new byte[] { 6, 26, 50, 74, 98, 122 },
new byte[] { 6, 30, 54, 78, 102, 126 },
new byte[] { 6, 26, 52, 78, 104, 130 },
new byte[] { 6, 30, 56, 82, 108, 134 },
new byte[] { 6, 34, 60, 86, 112, 138 },
new byte[] { 6, 30, 58, 86, 114, 142 },
new byte[] { 6, 34, 62, 90, 118, 146 },
new byte[] { 6, 30, 54, 78, 102, 126, 150 },
new byte[] { 6, 24, 50, 76, 102, 128, 154 },
new byte[] { 6, 28, 54, 80, 106, 132, 158 },
new byte[] { 6, 32, 58, 84, 110, 136, 162 },
new byte[] { 6, 26, 54, 82, 110, 138, 166 },
new byte[] { 6, 30, 58, 86, 114, 142, 170 }
};
// Table E.1 — Row/column coordinates of center module of Alignment Patterns
private static byte[][] AlignmentPatternCoordinatesByVersion { get; } =
new[]
{
Array.Empty<byte>(),
Array.Empty<byte>(),
new byte[] { 6, 18 },
new byte[] { 6, 22 },
new byte[] { 6, 26 },
new byte[] { 6, 30 },
new byte[] { 6, 34 },
new byte[] { 6, 22, 38 },
new byte[] { 6, 24, 42 },
new byte[] { 6, 26, 46 },
new byte[] { 6, 28, 50 },
new byte[] { 6, 30, 54 },
new byte[] { 6, 32, 58 },
new byte[] { 6, 34, 62 },
new byte[] { 6, 26, 46, 66 },
new byte[] { 6, 26, 48, 70 },
new byte[] { 6, 26, 50, 74 },
new byte[] { 6, 30, 54, 78 },
new byte[] { 6, 30, 56, 82 },
new byte[] { 6, 30, 58, 86 },
new byte[] { 6, 34, 62, 90 },
new byte[] { 6, 28, 50, 72, 94 },
new byte[] { 6, 26, 50, 74, 98 },
new byte[] { 6, 30, 54, 78, 102 },
new byte[] { 6, 28, 54, 80, 106 },
new byte[] { 6, 32, 58, 84, 110 },
new byte[] { 6, 30, 58, 86, 114 },
new byte[] { 6, 34, 62, 90, 118 },
new byte[] { 6, 26, 50, 74, 98, 122 },
new byte[] { 6, 30, 54, 78, 102, 126 },
new byte[] { 6, 26, 52, 78, 104, 130 },
new byte[] { 6, 30, 56, 82, 108, 134 },
new byte[] { 6, 34, 60, 86, 112, 138 },
new byte[] { 6, 30, 58, 86, 114, 142 },
new byte[] { 6, 34, 62, 90, 118, 146 },
new byte[] { 6, 30, 54, 78, 102, 126, 150 },
new byte[] { 6, 24, 50, 76, 102, 128, 154 },
new byte[] { 6, 28, 54, 80, 106, 132, 158 },
new byte[] { 6, 32, 58, 84, 110, 136, 162 },
new byte[] { 6, 26, 54, 82, 110, 138, 166 },
new byte[] { 6, 30, 58, 86, 114, 142, 170 }
};
public override void ApplyTo(TriStateMatrix matrix)
{
foreach (MatrixPoint coordinatePair in GetNonColidingCoordinatePairs(matrix))
{
CopyTo(matrix, coordinatePair, MatrixStatus.NoMask);
}
}
public override void ApplyTo(TriStateMatrix matrix)
{
foreach (MatrixPoint coordinatePair in GetNonColidingCoordinatePairs(matrix))
{
CopyTo(matrix, coordinatePair, MatrixStatus.NoMask);
}
}
public IEnumerable<MatrixPoint> GetNonColidingCoordinatePairs(TriStateMatrix matrix)
{
return
GetAllCoordinatePairs()
.Where(point => matrix.MStatus(point.Offset(2, 2)) == MatrixStatus.None);
}
public IEnumerable<MatrixPoint> GetNonColidingCoordinatePairs(TriStateMatrix matrix)
{
return
GetAllCoordinatePairs()
.Where(point => matrix.MStatus(point.Offset(2, 2)) == MatrixStatus.None);
}
private IEnumerable<MatrixPoint> GetAllCoordinatePairs()
{
IEnumerable<byte> coordinates = GetPatternCoordinatesByVersion(Version);
foreach (byte centerX in coordinates)
{
foreach (byte centerY in coordinates)
{
MatrixPoint location = new(centerX - 2, centerY - 2);
yield return location;
}
}
}
private IEnumerable<MatrixPoint> GetAllCoordinatePairs()
{
IEnumerable<byte> coordinates = GetPatternCoordinatesByVersion(Version);
foreach (byte centerX in coordinates)
{
foreach (byte centerY in coordinates)
{
MatrixPoint location = new(centerX - 2, centerY - 2);
yield return location;
}
}
}
private static IEnumerable<byte> GetPatternCoordinatesByVersion(int version)
{
return AlignmentPatternCoordinatesByVersion[version];
}
}
private static IEnumerable<byte> GetPatternCoordinatesByVersion(int version)
{
return AlignmentPatternCoordinatesByVersion[version];
}
}
@@ -1,17 +1,15 @@
using System;
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
internal class DarkDotAtLeftBottom : PatternStencilBase
{
public DarkDotAtLeftBottom(int version) : base(version)
{
}
public DarkDotAtLeftBottom(int version) : base(version)
{
}
public override bool[,] Stencil => throw new NotImplementedException();
public override bool[,] Stencil => throw new NotImplementedException();
public override void ApplyTo(TriStateMatrix matrix)
{
matrix[8, matrix.Width - 8, MatrixStatus.NoMask] = true;
}
}
public override void ApplyTo(TriStateMatrix matrix)
{
matrix[8, matrix.Width - 8, MatrixStatus.NoMask] = true;
}
}
@@ -1,32 +1,30 @@
using System;
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
internal abstract class PatternStencilBase : BitMatrix
{
protected const bool O = false;
protected const bool X = true;
protected const bool O = false;
protected const bool X = true;
internal PatternStencilBase(int version)
{
Version = version;
}
internal PatternStencilBase(int version)
{
Version = version;
}
public int Version { get; private set; }
public int Version { get; private set; }
public abstract bool[,] Stencil { get; }
public abstract bool[,] Stencil { get; }
public override int Width => Stencil.GetLength(0);
public override int Width => Stencil.GetLength(0);
public override int Height => Stencil.GetLength(1);
public override int Height => Stencil.GetLength(1);
public override bool[,] InternalArray => throw new NotImplementedException();
public override bool[,] InternalArray => throw new NotImplementedException();
public override bool this[int i, int j]
{
get => Stencil[i, j];
set => throw new NotSupportedException();
}
public override bool this[int i, int j]
{
get => Stencil[i, j];
set => throw new NotSupportedException();
}
public abstract void ApplyTo(TriStateMatrix matrix);
}
public abstract void ApplyTo(TriStateMatrix matrix);
}
@@ -2,40 +2,40 @@ namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
internal class PositionDetectionPattern : PatternStencilBase
{
public PositionDetectionPattern(int version)
: base(version)
{
}
public PositionDetectionPattern(int version)
: base(version)
{
}
private static bool[,] PositionDetection { get; } =
new[,]
{
{ O, O, O, O, O, O, O, O, O },
{ O, X, X, X, X, X, X, X, O },
{ O, X, O, O, O, O, O, X, O },
{ O, X, O, X, X, X, O, X, O },
{ O, X, O, X, X, X, O, X, O },
{ O, X, O, X, X, X, O, X, O },
{ O, X, O, O, O, O, O, X, O },
{ O, X, X, X, X, X, X, X, O },
{ O, O, O, O, O, O, O, O, O }
};
private static bool[,] PositionDetection { get; } =
new[,]
{
{ O, O, O, O, O, O, O, O, O },
{ O, X, X, X, X, X, X, X, O },
{ O, X, O, O, O, O, O, X, O },
{ O, X, O, X, X, X, O, X, O },
{ O, X, O, X, X, X, O, X, O },
{ O, X, O, X, X, X, O, X, O },
{ O, X, O, O, O, O, O, X, O },
{ O, X, X, X, X, X, X, X, O },
{ O, O, O, O, O, O, O, O, O }
};
public override bool[,] Stencil => PositionDetection;
public override bool[,] Stencil => PositionDetection;
public override void ApplyTo(TriStateMatrix matrix)
{
MatrixSize size = GetSizeOfSquareWithSeparators();
public override void ApplyTo(TriStateMatrix matrix)
{
MatrixSize size = GetSizeOfSquareWithSeparators();
MatrixPoint leftTopCorner = new(0, 0);
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 1), size), leftTopCorner, MatrixStatus.NoMask);
MatrixPoint leftTopCorner = new(0, 0);
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 1), size), leftTopCorner, MatrixStatus.NoMask);
MatrixPoint rightTopCorner = new(matrix.Width - Width + 1, 0);
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(0, 1), size), rightTopCorner, MatrixStatus.NoMask);
MatrixPoint rightTopCorner = new(matrix.Width - Width + 1, 0);
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(0, 1), size), rightTopCorner, MatrixStatus.NoMask);
MatrixPoint leftBottomCorner = new(0, matrix.Width - Width + 1);
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 0), size), leftBottomCorner, MatrixStatus.NoMask);
}
MatrixPoint leftBottomCorner = new(0, matrix.Width - Width + 1);
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 0), size), leftBottomCorner, MatrixStatus.NoMask);
}
private MatrixSize GetSizeOfSquareWithSeparators() => new(Width - 1, Height - 1);
}
private MatrixSize GetSizeOfSquareWithSeparators() => new(Width - 1, Height - 1);
}
@@ -1,35 +1,33 @@
using System;
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
internal class TimingPattern : PatternStencilBase
{
public TimingPattern(int version)
: base(version)
{
}
public TimingPattern(int version)
: base(version)
{
}
public override bool[,] Stencil => throw new NotImplementedException();
public override bool[,] Stencil => throw new NotImplementedException();
public override void ApplyTo(TriStateMatrix matrix)
{
// -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
// separation patterns (size 1). Thus, 8 = 7 + 1.
for (int i = 8; i < matrix.Width - 8; ++i)
{
bool value = (sbyte)((i + 1) % 2) == 1;
public override void ApplyTo(TriStateMatrix matrix)
{
// -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
// separation patterns (size 1). Thus, 8 = 7 + 1.
for (int i = 8; i < matrix.Width - 8; ++i)
{
bool value = (sbyte)((i + 1) % 2) == 1;
// Horizontal line.
if (matrix.MStatus(6, i) == MatrixStatus.None)
{
matrix[6, i, MatrixStatus.NoMask] = value;
}
// Horizontal line.
if (matrix.MStatus(6, i) == MatrixStatus.None)
{
matrix[6, i, MatrixStatus.NoMask] = value;
}
// Vertical line.
if (matrix.MStatus(i, 6) == MatrixStatus.None)
{
matrix[i, 6, MatrixStatus.NoMask] = value;
}
}
}
}
// Vertical line.
if (matrix.MStatus(i, 6) == MatrixStatus.None)
{
matrix[i, 6, MatrixStatus.NoMask] = value;
}
}
}
}
@@ -5,48 +5,48 @@ namespace Gma.QrCodeNet.Encoding;
/// </summary>
public static class QRCodeConstantVariable
{
public const int MinVersion = 1;
public const int MaxVersion = 40;
public const int MinVersion = 1;
public const int MaxVersion = 40;
public const string DefaultEncoding = "iso-8859-1";
public const string UTF8Encoding = "utf-8";
public const string DefaultEncoding = "iso-8859-1";
public const string UTF8Encoding = "utf-8";
/// <summary>
/// ISO/IEC 18004:2006(E) Page 45 Chapter Generating the error correction codewords
/// Primative Polynomial = Bin 100011101 = Dec 285
/// </summary>
public const int QRCodePrimitive = 285;
/// <summary>
/// ISO/IEC 18004:2006(E) Page 45 Chapter Generating the error correction codewords
/// Primative Polynomial = Bin 100011101 = Dec 285
/// </summary>
public const int QRCodePrimitive = 285;
internal const int TerminatorNPaddingBit = 0;
internal const int TerminatorNPaddingBit = 0;
internal const int TerminatorLength = 4;
internal const int TerminatorLength = 4;
/// <summary>
/// 0xEC
/// </summary>
internal const int PadeCodewordsOdd = 0xec;
/// <summary>
/// 0xEC
/// </summary>
internal const int PadeCodewordsOdd = 0xec;
/// <summary>
/// 0x11
/// </summary>
internal const int PadeCodewordsEven = 0x11;
/// <summary>
/// 0x11
/// </summary>
internal const int PadeCodewordsEven = 0x11;
internal const int PositionStencilWidth = 7;
internal const int PositionStencilWidth = 7;
internal static bool[] PadeOdd = new bool[]
{
true, true, true, false,
true, true, false, false
};
internal static bool[] PadeOdd = new bool[]
{
true, true, true, false,
true, true, false, false
};
internal static bool[] PadeEven = new bool[]
{
false, false, false, true,
false, false, false, true
};
internal static bool[] PadeEven = new bool[]
{
false, false, false, true,
false, false, false, true
};
/// <summary>
/// URL:http://en.wikipedia.org/wiki/Byte-order_mark
/// </summary>
public static byte[] UTF8ByteOrderMark => new byte[] { 0xEF, 0xBB, 0xBF };
}
/// <summary>
/// URL:http://en.wikipedia.org/wiki/Byte-order_mark
/// </summary>
public static byte[] UTF8ByteOrderMark => new byte[] { 0xEF, 0xBB, 0xBF };
}
@@ -9,24 +9,24 @@ namespace Gma.QrCodeNet.Encoding;
internal static class QRCodeEncode
{
internal static BitMatrix Encode(string content, ErrorCorrectionLevel errorLevel)
{
EncodationStruct encodeStruct = DataEncode.Encode(content, errorLevel);
internal static BitMatrix Encode(string content, ErrorCorrectionLevel errorLevel)
{
EncodationStruct encodeStruct = DataEncode.Encode(content, errorLevel);
return ProcessEncodationResult(encodeStruct, errorLevel);
}
return ProcessEncodationResult(encodeStruct, errorLevel);
}
private static BitMatrix ProcessEncodationResult(EncodationStruct encodeStruct, ErrorCorrectionLevel errorLevel)
{
BitList codewords = ECGenerator.FillECCodewords(encodeStruct.DataCodewords, encodeStruct.VersionDetail);
private static BitMatrix ProcessEncodationResult(EncodationStruct encodeStruct, ErrorCorrectionLevel errorLevel)
{
BitList codewords = ECGenerator.FillECCodewords(encodeStruct.DataCodewords, encodeStruct.VersionDetail);
TriStateMatrix triMatrix = new(encodeStruct.VersionDetail.MatrixWidth);
PositioningPatternBuilder.EmbedBasicPatterns(encodeStruct.VersionDetail.Version, triMatrix);
TriStateMatrix triMatrix = new(encodeStruct.VersionDetail.MatrixWidth);
PositioningPatternBuilder.EmbedBasicPatterns(encodeStruct.VersionDetail.Version, triMatrix);
triMatrix.EmbedVersionInformation(encodeStruct.VersionDetail.Version);
triMatrix.EmbedFormatInformation(errorLevel, new Pattern0());
triMatrix.TryEmbedCodewords(codewords);
triMatrix.EmbedVersionInformation(encodeStruct.VersionDetail.Version);
triMatrix.EmbedFormatInformation(errorLevel, new Pattern0());
triMatrix.TryEmbedCodewords(codewords);
return triMatrix.GetLowestPenaltyMatrix(errorLevel);
}
}
return triMatrix.GetLowestPenaltyMatrix(errorLevel);
}
}
@@ -8,21 +8,21 @@ namespace Gma.QrCodeNet.Encoding;
/// </summary>
public class QrCode
{
internal QrCode(BitMatrix matrix)
{
Matrix = matrix;
IsContainMatrix = true;
}
internal QrCode(BitMatrix matrix)
{
Matrix = matrix;
IsContainMatrix = true;
}
public bool IsContainMatrix
{
get;
private set;
}
public bool IsContainMatrix
{
get;
private set;
}
public BitMatrix Matrix
{
get;
private set;
}
}
public BitMatrix Matrix
{
get;
private set;
}
}
@@ -2,38 +2,38 @@ namespace Gma.QrCodeNet.Encoding;
public class QrEncoder
{
/// <summary>
/// Default QrEncoder will set ErrorCorrectionLevel as M
/// </summary>
public QrEncoder()
: this(ErrorCorrectionLevel.M)
{
}
/// <summary>
/// Default QrEncoder will set ErrorCorrectionLevel as M
/// </summary>
public QrEncoder()
: this(ErrorCorrectionLevel.M)
{
}
/// <summary>
/// QrEncoder with parameter ErrorCorrectionLevel.
/// </summary>
public QrEncoder(ErrorCorrectionLevel errorCorrectionLevel)
{
ErrorCorrectionLevel = errorCorrectionLevel;
}
/// <summary>
/// QrEncoder with parameter ErrorCorrectionLevel.
/// </summary>
public QrEncoder(ErrorCorrectionLevel errorCorrectionLevel)
{
ErrorCorrectionLevel = errorCorrectionLevel;
}
public ErrorCorrectionLevel ErrorCorrectionLevel { get; set; }
public ErrorCorrectionLevel ErrorCorrectionLevel { get; set; }
/// <summary>
/// Encode string content to QrCode matrix
/// </summary>
/// <exception cref="InputOutOfBoundaryException">
/// This exception for string content is null, empty or too large</exception>
public QrCode Encode(string content)
{
if (string.IsNullOrEmpty(content))
{
throw new InputOutOfBoundaryException("Input cannot be null or empty.");
}
else
{
return new QrCode(QRCodeEncode.Encode(content, ErrorCorrectionLevel));
}
}
}
/// <summary>
/// Encode string content to QrCode matrix
/// </summary>
/// <exception cref="InputOutOfBoundaryException">
/// This exception for string content is null, empty or too large</exception>
public QrCode Encode(string content)
{
if (string.IsNullOrEmpty(content))
{
throw new InputOutOfBoundaryException("Input cannot be null or empty.");
}
else
{
return new QrCode(QRCodeEncode.Encode(content, ErrorCorrectionLevel));
}
}
}
@@ -1,5 +1,3 @@
using System;
namespace Gma.QrCodeNet.Encoding.ReedSolomon;
/// <summary>
@@ -7,116 +5,116 @@ namespace Gma.QrCodeNet.Encoding.ReedSolomon;
/// </summary>
internal sealed class GaloisField256
{
internal GaloisField256(int primitive)
{
AntiLogTable = new int[256];
LogTable = new int[256];
internal GaloisField256(int primitive)
{
AntiLogTable = new int[256];
LogTable = new int[256];
Primitive = primitive;
Primitive = primitive;
int gfx = 1;
int gfx = 1;
// Power cycle is from 0 to 254. 2^255 = 1 = 2^0
// Value cycle is from 1 to 255. Thus there should not have Log(0).
for (int powers = 0; powers < 256; powers++)
{
AntiLogTable[powers] = gfx;
if (powers != 255)
{
LogTable[gfx] = powers;
}
// Power cycle is from 0 to 254. 2^255 = 1 = 2^0
// Value cycle is from 1 to 255. Thus there should not have Log(0).
for (int powers = 0; powers < 256; powers++)
{
AntiLogTable[powers] = gfx;
if (powers != 255)
{
LogTable[gfx] = powers;
}
gfx <<= 1; // gfx = gfx * 2 where alpha is 2.
gfx <<= 1; // gfx = gfx * 2 where alpha is 2.
if (gfx > 255)
{
gfx ^= primitive;
}
}
}
if (gfx > 255)
{
gfx ^= primitive;
}
}
}
private int[] AntiLogTable { get; }
private int[] LogTable { get; }
private int[] AntiLogTable { get; }
private int[] LogTable { get; }
internal int Primitive { get; }
internal int Primitive { get; }
internal static GaloisField256 QRCodeGaloisField => new(QRCodeConstantVariable.QRCodePrimitive);
internal static GaloisField256 QRCodeGaloisField => new(QRCodeConstantVariable.QRCodePrimitive);
/// <returns>
/// Powers of a in GF table. Where a = 2
/// </returns>
internal int Exponent(int powersOfa) => AntiLogTable[powersOfa];
/// <returns>
/// Powers of a in GF table. Where a = 2
/// </returns>
internal int Exponent(int powersOfa) => AntiLogTable[powersOfa];
/// <returns>
/// Log (power of a) in GF table. Where a = 2
/// </returns>
internal int Log(int gfValue)
{
if (gfValue == 0)
{
throw new ArgumentException("GaloisField value will not be equal to 0, Log method.");
}
/// <returns>
/// Log (power of a) in GF table. Where a = 2
/// </returns>
internal int Log(int gfValue)
{
if (gfValue == 0)
{
throw new ArgumentException("GaloisField value will not be equal to 0, Log method.");
}
return LogTable[gfValue];
}
return LogTable[gfValue];
}
internal int Inverse(int gfValue)
{
if (gfValue == 0)
{
throw new ArgumentException("GaloisField value will not be equal to 0, Inverse method.");
}
internal int Inverse(int gfValue)
{
if (gfValue == 0)
{
throw new ArgumentException("GaloisField value will not be equal to 0, Inverse method.");
}
return Exponent(255 - Log(gfValue));
}
return Exponent(255 - Log(gfValue));
}
internal int Addition(int gfValueA, int gfValueB) => gfValueA ^ gfValueB;
internal int Addition(int gfValueA, int gfValueB) => gfValueA ^ gfValueB;
internal int Subtraction(int gfValueA, int gfValueB) => Addition(gfValueA, gfValueB); // Subtraction is same as addition.
internal int Subtraction(int gfValueA, int gfValueB) => Addition(gfValueA, gfValueB); // Subtraction is same as addition.
/// <returns>
/// Product of two values.
/// In other words. a multiply b
/// </returns>
internal int Product(int gfValueA, int gfValueB)
{
if (gfValueA == 0 || gfValueB == 0)
{
return 0;
}
if (gfValueA == 1)
{
return gfValueB;
}
if (gfValueB == 1)
{
return gfValueA;
}
/// <returns>
/// Product of two values.
/// In other words. a multiply b
/// </returns>
internal int Product(int gfValueA, int gfValueB)
{
if (gfValueA == 0 || gfValueB == 0)
{
return 0;
}
if (gfValueA == 1)
{
return gfValueB;
}
if (gfValueB == 1)
{
return gfValueA;
}
return Exponent((Log(gfValueA) + Log(gfValueB)) % 255);
}
return Exponent((Log(gfValueA) + Log(gfValueB)) % 255);
}
/// <returns>
/// Quotient of two values.
/// In other words. a divided b
/// </returns>
internal int Quotient(int gfValueA, int gfValueB)
{
if (gfValueA == 0)
{
return 0;
}
/// <returns>
/// Quotient of two values.
/// In other words. a divided b
/// </returns>
internal int Quotient(int gfValueA, int gfValueB)
{
if (gfValueA == 0)
{
return 0;
}
if (gfValueB == 0)
{
throw new ArgumentException($"{nameof(gfValueB)} cannot be zero.");
}
if (gfValueB == 0)
{
throw new ArgumentException($"{nameof(gfValueB)} cannot be zero.");
}
if (gfValueB == 1)
{
return gfValueA;
}
if (gfValueB == 1)
{
return gfValueA;
}
return Exponent(Math.Abs(Log(gfValueA) - Log(gfValueB)) % 255);
}
}
return Exponent(Math.Abs(Log(gfValueA) - Log(gfValueB)) % 255);
}
}
@@ -1,5 +1,3 @@
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.ReedSolomon;
/// <summary>
@@ -7,56 +5,56 @@ namespace Gma.QrCodeNet.Encoding.ReedSolomon;
/// </summary>
internal sealed class GeneratorPolynomial
{
/// <summary>
/// After create GeneratorPolynomial. Keep it as long as possible.
/// Unless QRCode encode is done or no more QRCode need to generate.
/// </summary>
internal GeneratorPolynomial(GaloisField256 gfield)
{
Gfield = gfield;
CacheGenerator = new List<Polynomial>(10)
{
new Polynomial(Gfield, new int[] { 1 })
};
}
/// <summary>
/// After create GeneratorPolynomial. Keep it as long as possible.
/// Unless QRCode encode is done or no more QRCode need to generate.
/// </summary>
internal GeneratorPolynomial(GaloisField256 gfield)
{
Gfield = gfield;
CacheGenerator = new List<Polynomial>(10)
{
new Polynomial(Gfield, new int[] { 1 })
};
}
private GaloisField256 Gfield { get; }
private GaloisField256 Gfield { get; }
private List<Polynomial> CacheGenerator { get; }
private List<Polynomial> CacheGenerator { get; }
/// <summary>
/// Get generator by degree. (Largest degree for that generator)
/// </summary>
/// <returns>Generator</returns>
internal Polynomial GetGenerator(int degree)
{
if (degree >= CacheGenerator.Count)
{
BuildGenerator(degree);
}
/// <summary>
/// Get generator by degree. (Largest degree for that generator)
/// </summary>
/// <returns>Generator</returns>
internal Polynomial GetGenerator(int degree)
{
if (degree >= CacheGenerator.Count)
{
BuildGenerator(degree);
}
return CacheGenerator[degree];
}
return CacheGenerator[degree];
}
/// <summary>
/// Build Generator if we cannot find specific degree of generator from cache
/// </summary>
private void BuildGenerator(int degree)
{
lock (CacheGenerator)
{
int currentCacheLength = CacheGenerator.Count;
if (degree >= currentCacheLength)
{
Polynomial lastGenerator = CacheGenerator[currentCacheLength - 1];
/// <summary>
/// Build Generator if we cannot find specific degree of generator from cache
/// </summary>
private void BuildGenerator(int degree)
{
lock (CacheGenerator)
{
int currentCacheLength = CacheGenerator.Count;
if (degree >= currentCacheLength)
{
Polynomial lastGenerator = CacheGenerator[currentCacheLength - 1];
for (int d = currentCacheLength; d <= degree; d++)
{
Polynomial nextGenerator = lastGenerator.Multiply(new Polynomial(Gfield, new int[] { 1, Gfield.Exponent(d - 1) }));
CacheGenerator.Add(nextGenerator);
lastGenerator = nextGenerator;
}
}
}
}
}
for (int d = currentCacheLength; d <= degree; d++)
{
Polynomial nextGenerator = lastGenerator.Multiply(new Polynomial(Gfield, new int[] { 1, Gfield.Exponent(d - 1) }));
CacheGenerator.Add(nextGenerator);
lastGenerator = nextGenerator;
}
}
}
}
}
@@ -2,14 +2,14 @@ namespace Gma.QrCodeNet.Encoding.ReedSolomon;
internal struct PolyDivideStruct
{
internal PolyDivideStruct(Polynomial quotient, Polynomial remainder)
: this()
{
Quotient = quotient;
Remainder = remainder;
}
internal PolyDivideStruct(Polynomial quotient, Polynomial remainder)
: this()
{
Quotient = quotient;
Remainder = remainder;
}
internal Polynomial Quotient { get; private set; }
internal Polynomial Quotient { get; private set; }
internal Polynomial Remainder { get; private set; }
}
internal Polynomial Remainder { get; private set; }
}
@@ -1,242 +1,240 @@
using System;
namespace Gma.QrCodeNet.Encoding.ReedSolomon;
internal sealed class Polynomial
{
internal Polynomial(GaloisField256 gfield, int[] coefficients)
{
int coefficientsLength = coefficients.Length;
internal Polynomial(GaloisField256 gfield, int[] coefficients)
{
int coefficientsLength = coefficients.Length;
if (coefficientsLength == 0 || coefficients is null)
{
throw new ArithmeticException($"Cannot create empty {nameof(Polynomial)}.");
}
if (coefficientsLength == 0 || coefficients is null)
{
throw new ArithmeticException($"Cannot create empty {nameof(Polynomial)}.");
}
GField = gfield;
GField = gfield;
Primitive = gfield.Primitive;
Primitive = gfield.Primitive;
if (coefficientsLength > 1 && coefficients[0] == 0)
{
int firstNonZeroIndex = 1;
while (firstNonZeroIndex < coefficientsLength && coefficients[firstNonZeroIndex] == 0)
{
firstNonZeroIndex++;
}
if (coefficientsLength > 1 && coefficients[0] == 0)
{
int firstNonZeroIndex = 1;
while (firstNonZeroIndex < coefficientsLength && coefficients[firstNonZeroIndex] == 0)
{
firstNonZeroIndex++;
}
if (firstNonZeroIndex == coefficientsLength)
{
Coefficients = new int[] { 0 };
}
else
{
int newLength = coefficientsLength - firstNonZeroIndex;
Coefficients = new int[newLength];
Array.Copy(coefficients, firstNonZeroIndex, Coefficients, 0, newLength);
}
}
else
{
Coefficients = new int[coefficientsLength];
Array.Copy(coefficients, Coefficients, coefficientsLength);
}
}
if (firstNonZeroIndex == coefficientsLength)
{
Coefficients = new int[] { 0 };
}
else
{
int newLength = coefficientsLength - firstNonZeroIndex;
Coefficients = new int[newLength];
Array.Copy(coefficients, firstNonZeroIndex, Coefficients, 0, newLength);
}
}
else
{
Coefficients = new int[coefficientsLength];
Array.Copy(coefficients, Coefficients, coefficientsLength);
}
}
internal int[] Coefficients { get; }
internal int[] Coefficients { get; }
internal GaloisField256 GField { get; }
internal GaloisField256 GField { get; }
internal int Degree => Coefficients.Length - 1;
internal int Degree => Coefficients.Length - 1;
internal int Primitive { get; }
internal int Primitive { get; }
internal bool IsMonomialZero => Coefficients[0] == 0;
internal bool IsMonomialZero => Coefficients[0] == 0;
/// <returns>
/// Coefficient position. where (coefficient)x^degree
/// </returns>
internal int GetCoefficient(int degree)
{
// Eg: x^2 + x + 1. degree 1, reverse position = degree + 1 = 2.
// Pos = 3 - 2 = 1
return Coefficients[^(degree + 1)];
}
/// <returns>
/// Coefficient position. where (coefficient)x^degree
/// </returns>
internal int GetCoefficient(int degree)
{
// Eg: x^2 + x + 1. degree 1, reverse position = degree + 1 = 2.
// Pos = 3 - 2 = 1
return Coefficients[^(degree + 1)];
}
/// <summary>
/// Add another Polynomial to current one
/// </summary>
/// <param name="other">The polynomial need to add or subtract to current one</param>
/// <returns>Result polynomial after add or subtract</returns>
internal Polynomial AddOrSubtract(Polynomial other)
{
if (Primitive != other.Primitive)
{
throw new ArgumentException($"{nameof(Polynomial)} cannot perform {nameof(AddOrSubtract)} as they do not have the same {nameof(Primitive)}" +
$" for {nameof(GaloisField256)}.");
}
if (IsMonomialZero)
{
return other;
}
else if (other.IsMonomialZero)
{
return this;
}
/// <summary>
/// Add another Polynomial to current one
/// </summary>
/// <param name="other">The polynomial need to add or subtract to current one</param>
/// <returns>Result polynomial after add or subtract</returns>
internal Polynomial AddOrSubtract(Polynomial other)
{
if (Primitive != other.Primitive)
{
throw new ArgumentException($"{nameof(Polynomial)} cannot perform {nameof(AddOrSubtract)} as they do not have the same {nameof(Primitive)}" +
$" for {nameof(GaloisField256)}.");
}
if (IsMonomialZero)
{
return other;
}
else if (other.IsMonomialZero)
{
return this;
}
int otherLength = other.Coefficients.Length;
int thisLength = Coefficients.Length;
int otherLength = other.Coefficients.Length;
int thisLength = Coefficients.Length;
if (otherLength > thisLength)
{
return CoefficientXor(Coefficients, other.Coefficients);
}
else
{
return CoefficientXor(other.Coefficients, Coefficients);
}
}
if (otherLength > thisLength)
{
return CoefficientXor(Coefficients, other.Coefficients);
}
else
{
return CoefficientXor(other.Coefficients, Coefficients);
}
}
internal Polynomial CoefficientXor(int[] smallerCoefficients, int[] largerCoefficients)
{
if (smallerCoefficients.Length > largerCoefficients.Length)
{
throw new ArgumentException($"Cannot perform {nameof(CoefficientXor)} method as smaller {nameof(Coefficients)} length is greater than the larger one.");
}
internal Polynomial CoefficientXor(int[] smallerCoefficients, int[] largerCoefficients)
{
if (smallerCoefficients.Length > largerCoefficients.Length)
{
throw new ArgumentException($"Cannot perform {nameof(CoefficientXor)} method as smaller {nameof(Coefficients)} length is greater than the larger one.");
}
int targetLength = largerCoefficients.Length;
int[] xorCoefficient = new int[targetLength];
int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length;
int targetLength = largerCoefficients.Length;
int[] xorCoefficient = new int[targetLength];
int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length;
Array.Copy(largerCoefficients, 0, xorCoefficient, 0, lengthDiff);
Array.Copy(largerCoefficients, 0, xorCoefficient, 0, lengthDiff);
for (int index = lengthDiff; index < targetLength; index++)
{
xorCoefficient[index] = GField.Addition(largerCoefficients[index], smallerCoefficients[index - lengthDiff]);
}
for (int index = lengthDiff; index < targetLength; index++)
{
xorCoefficient[index] = GField.Addition(largerCoefficients[index], smallerCoefficients[index - lengthDiff]);
}
return new Polynomial(GField, xorCoefficient);
}
return new Polynomial(GField, xorCoefficient);
}
/// <summary>
/// Multiply current Polynomial to another one.
/// </summary>
/// <returns>Result polynomial after multiply</returns>
internal Polynomial Multiply(Polynomial other)
{
if (Primitive != other.Primitive)
{
throw new ArgumentException($"{nameof(Polynomial)} cannot perform {nameof(Multiply)} as they do not have the same {nameof(Primitive)}" +
$" for {nameof(GaloisField256)}.");
}
if (IsMonomialZero || other.IsMonomialZero)
{
return new Polynomial(GField, new int[] { 0 });
}
/// <summary>
/// Multiply current Polynomial to another one.
/// </summary>
/// <returns>Result polynomial after multiply</returns>
internal Polynomial Multiply(Polynomial other)
{
if (Primitive != other.Primitive)
{
throw new ArgumentException($"{nameof(Polynomial)} cannot perform {nameof(Multiply)} as they do not have the same {nameof(Primitive)}" +
$" for {nameof(GaloisField256)}.");
}
if (IsMonomialZero || other.IsMonomialZero)
{
return new Polynomial(GField, new int[] { 0 });
}
int[] aCoefficients = Coefficients;
int aLength = aCoefficients.Length;
int[] bCoefficient = other.Coefficients;
int bLength = bCoefficient.Length;
int[] rCoefficients = new int[aLength + bLength - 1];
int[] aCoefficients = Coefficients;
int aLength = aCoefficients.Length;
int[] bCoefficient = other.Coefficients;
int bLength = bCoefficient.Length;
int[] rCoefficients = new int[aLength + bLength - 1];
for (int aIndex = 0; aIndex < aLength; aIndex++)
{
int aCoeff = aCoefficients[aIndex];
for (int bIndex = 0; bIndex < bLength; bIndex++)
{
rCoefficients[aIndex + bIndex] =
GField.Addition(rCoefficients[aIndex + bIndex], GField.Product(aCoeff, bCoefficient[bIndex]));
}
}
return new Polynomial(GField, rCoefficients);
}
for (int aIndex = 0; aIndex < aLength; aIndex++)
{
int aCoeff = aCoefficients[aIndex];
for (int bIndex = 0; bIndex < bLength; bIndex++)
{
rCoefficients[aIndex + bIndex] =
GField.Addition(rCoefficients[aIndex + bIndex], GField.Product(aCoeff, bCoefficient[bIndex]));
}
}
return new Polynomial(GField, rCoefficients);
}
/// <summary>
/// Multiplay scalar to current polynomial
/// </summary>
/// <returns>Result of polynomial after multiply scalar</returns>
internal Polynomial MultiplyScalar(int scalar)
{
if (scalar == 0)
{
return new Polynomial(GField, new int[] { 0 });
}
else if (scalar == 1)
{
return this;
}
/// <summary>
/// Multiplay scalar to current polynomial
/// </summary>
/// <returns>Result of polynomial after multiply scalar</returns>
internal Polynomial MultiplyScalar(int scalar)
{
if (scalar == 0)
{
return new Polynomial(GField, new int[] { 0 });
}
else if (scalar == 1)
{
return this;
}
int length = Coefficients.Length;
int[] rCoefficient = new int[length];
int length = Coefficients.Length;
int[] rCoefficient = new int[length];
for (int index = 0; index < length; index++)
{
rCoefficient[index] = GField.Product(Coefficients[index], scalar);
}
for (int index = 0; index < length; index++)
{
rCoefficient[index] = GField.Product(Coefficients[index], scalar);
}
return new Polynomial(GField, rCoefficient);
}
return new Polynomial(GField, rCoefficient);
}
/// <summary>
/// Divide current polynomial by "other"
/// </summary>
/// <returns>Result polynomial after divide</returns>
internal PolyDivideStruct Divide(Polynomial other)
{
if (Primitive != other.Primitive)
{
throw new ArgumentException($"{nameof(Polynomial)} cannot perform {nameof(Divide)} as they do not have the same {nameof(Primitive)}" +
$" for {nameof(GaloisField256)}.");
}
if (other.IsMonomialZero)
{
throw new ArgumentException($"Cannot divide by {nameof(Polynomial)} Zero.");
}
/// <summary>
/// Divide current polynomial by "other"
/// </summary>
/// <returns>Result polynomial after divide</returns>
internal PolyDivideStruct Divide(Polynomial other)
{
if (Primitive != other.Primitive)
{
throw new ArgumentException($"{nameof(Polynomial)} cannot perform {nameof(Divide)} as they do not have the same {nameof(Primitive)}" +
$" for {nameof(GaloisField256)}.");
}
if (other.IsMonomialZero)
{
throw new ArgumentException($"Cannot divide by {nameof(Polynomial)} Zero.");
}
// This divide by other = a divide by b
int aLength = Coefficients.Length;
// This divide by other = a divide by b
int aLength = Coefficients.Length;
// We will make change to aCoefficient. It will return as remainder
int[] aCoefficients = new int[aLength];
Array.Copy(Coefficients, 0, aCoefficients, 0, aLength);
// We will make change to aCoefficient. It will return as remainder
int[] aCoefficients = new int[aLength];
Array.Copy(Coefficients, 0, aCoefficients, 0, aLength);
int bLength = other.Coefficients.Length;
int bLength = other.Coefficients.Length;
if (aLength < bLength)
{
return new PolyDivideStruct(new Polynomial(GField, new int[] { 0 }), this);
}
else
{
// Quotient coefficients
// qLastIndex = alength - blength qlength = qLastIndex + 1
int[] qCoefficients = new int[(aLength - bLength) + 1];
if (aLength < bLength)
{
return new PolyDivideStruct(new Polynomial(GField, new int[] { 0 }), this);
}
else
{
// Quotient coefficients
// qLastIndex = alength - blength qlength = qLastIndex + 1
int[] qCoefficients = new int[(aLength - bLength) + 1];
// Denominator
int otherLeadingTerm = other.GetCoefficient(other.Degree);
int inverseOtherLeadingTerm = GField.Inverse(otherLeadingTerm);
// Denominator
int otherLeadingTerm = other.GetCoefficient(other.Degree);
int inverseOtherLeadingTerm = GField.Inverse(otherLeadingTerm);
for (int aIndex = 0; aIndex <= aLength - bLength; aIndex++)
{
if (aCoefficients[aIndex] != 0)
{
int aScalar = GField.Product(inverseOtherLeadingTerm, aCoefficients[aIndex]);
Polynomial term = other.MultiplyScalar(aScalar);
qCoefficients[aIndex] = aScalar;
for (int aIndex = 0; aIndex <= aLength - bLength; aIndex++)
{
if (aCoefficients[aIndex] != 0)
{
int aScalar = GField.Product(inverseOtherLeadingTerm, aCoefficients[aIndex]);
Polynomial term = other.MultiplyScalar(aScalar);
qCoefficients[aIndex] = aScalar;
int[] bCoefficient = term.Coefficients;
if (bCoefficient[0] != 0)
{
for (int bIndex = 0; bIndex < bLength; bIndex++)
{
aCoefficients[aIndex + bIndex] = GField.Subtraction(aCoefficients[aIndex + bIndex], bCoefficient[bIndex]);
}
}
}
}
int[] bCoefficient = term.Coefficients;
if (bCoefficient[0] != 0)
{
for (int bIndex = 0; bIndex < bLength; bIndex++)
{
aCoefficients[aIndex + bIndex] = GField.Subtraction(aCoefficients[aIndex + bIndex], bCoefficient[bIndex]);
}
}
}
}
return new PolyDivideStruct(new Polynomial(GField, qCoefficients), new Polynomial(GField, aCoefficients));
}
}
}
return new PolyDivideStruct(new Polynomial(GField, qCoefficients), new Polynomial(GField, aCoefficients));
}
}
}
@@ -1,91 +1,89 @@
using System;
namespace Gma.QrCodeNet.Encoding.ReedSolomon;
internal sealed class ReedSolomonEncoder
{
/// <summary>
/// Encode an array of data codeword with GaloisField 256.
/// </summary>
/// <param name="dataBytes">Array of data codewords for a single block.</param>
/// <param name="numECBytes">Number of error correction codewords for data codewords</param>
/// <param name="generatorPoly">Cached or newly create GeneratorPolynomial</param>
/// <returns>Return error correction codewords array</returns>
internal static byte[] Encode(byte[] dataBytes, int numECBytes, GeneratorPolynomial generatorPoly)
{
int dataLength = dataBytes.Length;
/// <summary>
/// Encode an array of data codeword with GaloisField 256.
/// </summary>
/// <param name="dataBytes">Array of data codewords for a single block.</param>
/// <param name="numECBytes">Number of error correction codewords for data codewords</param>
/// <param name="generatorPoly">Cached or newly create GeneratorPolynomial</param>
/// <returns>Return error correction codewords array</returns>
internal static byte[] Encode(byte[] dataBytes, int numECBytes, GeneratorPolynomial generatorPoly)
{
int dataLength = dataBytes.Length;
if (generatorPoly == null)
throw new ArgumentNullException(nameof(generatorPoly));
if (dataLength == 0)
{
throw new ArgumentException("There is no data bytes to encode.");
}
{
throw new ArgumentException("There is no data bytes to encode.");
}
if (numECBytes <= 0)
{
throw new ArgumentException("No Error Correction bytes.");
}
if (numECBytes <= 0)
{
throw new ArgumentException("No Error Correction bytes.");
}
int[] toEncode = ConvertToIntArray(dataBytes, dataLength, numECBytes);
int[] toEncode = ConvertToIntArray(dataBytes, dataLength, numECBytes);
Polynomial generator = generatorPoly.GetGenerator(numECBytes);
Polynomial generator = generatorPoly.GetGenerator(numECBytes);
Polynomial dataPoly = new(generator.GField, toEncode);
Polynomial dataPoly = new(generator.GField, toEncode);
PolyDivideStruct divideResult = dataPoly.Divide(generator);
PolyDivideStruct divideResult = dataPoly.Divide(generator);
int[] remainderCoeffs = divideResult.Remainder.Coefficients;
int[] remainderCoeffs = divideResult.Remainder.Coefficients;
return ConvertTosByteArray(remainderCoeffs, numECBytes);
}
return ConvertTosByteArray(remainderCoeffs, numECBytes);
}
/// <summary>
/// Convert data codewords to int array. And add error correction space at end of that array
/// </summary>
/// <param name="dataBytes">Data codewords array</param>
/// <param name="dataLength">Data codewords length</param>
/// <param name="numECBytes">Num of error correction bytes</param>
/// <returns>Int array for data codewords array follow by error correction space</returns>
private static int[] ConvertToIntArray(byte[] dataBytes, int dataLength, int numECBytes)
{
int[] resultArray = new int[dataLength + numECBytes];
/// <summary>
/// Convert data codewords to int array. And add error correction space at end of that array
/// </summary>
/// <param name="dataBytes">Data codewords array</param>
/// <param name="dataLength">Data codewords length</param>
/// <param name="numECBytes">Num of error correction bytes</param>
/// <returns>Int array for data codewords array follow by error correction space</returns>
private static int[] ConvertToIntArray(byte[] dataBytes, int dataLength, int numECBytes)
{
int[] resultArray = new int[dataLength + numECBytes];
for (int index = 0; index < dataLength; index++)
{
resultArray[index] = dataBytes[index] & 0xff;
}
for (int index = 0; index < dataLength; index++)
{
resultArray[index] = dataBytes[index] & 0xff;
}
return resultArray;
}
return resultArray;
}
/// <summary>
/// Reassembly error correction codewords. As Polynomial class will eliminate zero monomial at front.
/// </summary>
/// <param name="remainder">Remainder byte array after divide. </param>
/// <param name="numECBytes">Error correction codewords length</param>
/// <returns>Error correction codewords</returns>
private static byte[] ConvertTosByteArray(int[] remainder, int numECBytes)
{
int remainderLength = remainder.Length;
if (remainderLength > numECBytes)
{
throw new ArgumentException($"Num of {nameof(remainder)} bytes cannot be larger than {nameof(numECBytes)}.");
}
/// <summary>
/// Reassembly error correction codewords. As Polynomial class will eliminate zero monomial at front.
/// </summary>
/// <param name="remainder">Remainder byte array after divide. </param>
/// <param name="numECBytes">Error correction codewords length</param>
/// <returns>Error correction codewords</returns>
private static byte[] ConvertTosByteArray(int[] remainder, int numECBytes)
{
int remainderLength = remainder.Length;
if (remainderLength > numECBytes)
{
throw new ArgumentException($"Num of {nameof(remainder)} bytes cannot be larger than {nameof(numECBytes)}.");
}
int numZeroCoeffs = numECBytes - remainderLength;
int numZeroCoeffs = numECBytes - remainderLength;
byte[] resultArray = new byte[numECBytes];
for (int index = 0; index < numZeroCoeffs; index++)
{
resultArray[index] = 0;
}
byte[] resultArray = new byte[numECBytes];
for (int index = 0; index < numZeroCoeffs; index++)
{
resultArray[index] = 0;
}
for (int rIndex = 0; rIndex < remainderLength; rIndex++)
{
resultArray[numZeroCoeffs + rIndex] = (byte)remainder[rIndex];
}
for (int rIndex = 0; rIndex < remainderLength; rIndex++)
{
resultArray[numZeroCoeffs + rIndex] = (byte)remainder[rIndex];
}
return resultArray;
}
}
return resultArray;
}
}
@@ -2,27 +2,27 @@ namespace Gma.QrCodeNet.Encoding;
public sealed class StateMatrix
{
public StateMatrix(int width)
{
Width = width;
MatrixStatus = new MatrixStatus[width, width];
}
public StateMatrix(int width)
{
Width = width;
MatrixStatus = new MatrixStatus[width, width];
}
private MatrixStatus[,] MatrixStatus { get; }
private MatrixStatus[,] MatrixStatus { get; }
public MatrixStatus this[int x, int y]
{
get => MatrixStatus[x, y];
set => MatrixStatus[x, y] = value;
}
public MatrixStatus this[int x, int y]
{
get => MatrixStatus[x, y];
set => MatrixStatus[x, y] = value;
}
internal MatrixStatus this[MatrixPoint point]
{
get => this[point.X, point.Y];
set => this[point.X, point.Y] = value;
}
internal MatrixStatus this[MatrixPoint point]
{
get => this[point.X, point.Y];
set => this[point.X, point.Y] = value;
}
public int Width { get; }
public int Width { get; }
public int Height => Width;
}
public int Height => Width;
}
@@ -1,73 +1,71 @@
using System;
namespace Gma.QrCodeNet.Encoding.Terminate;
internal static class Terminator
{
private const int NumBitsForByte = 8;
private const int NumBitsForByte = 8;
/// <summary>
/// This method will create BitList that contains
/// terminator, padding and pad codewords for given datacodewords.
/// Use it to full fill the data codewords capacity. Thus avoid massive empty bits.
/// </summary>
/// <remarks>ISO/IEC 18004:2006 P. 32 33.
/// Terminator / Bit stream to codeword conversion</remarks>
/// <param name="baseList">Method will add terminator bits (Terminator, padding and padcodewords) at end of baseList</param>
/// <param name="dataCount">Num of bits for datacodewords without terminator</param>
/// <param name="numTotalDataCodewords">Total number of datacodewords for specific version.
/// Receive it under Version/VersionTable</param>
internal static void TerminateBites(this BitList baseList, int dataCount, int numTotalDataCodewords)
{
int numTotalDataBits = numTotalDataCodewords << 3;
int numDataBits = dataCount;
/// <summary>
/// This method will create BitList that contains
/// terminator, padding and pad codewords for given datacodewords.
/// Use it to full fill the data codewords capacity. Thus avoid massive empty bits.
/// </summary>
/// <remarks>ISO/IEC 18004:2006 P. 32 33.
/// Terminator / Bit stream to codeword conversion</remarks>
/// <param name="baseList">Method will add terminator bits (Terminator, padding and padcodewords) at end of baseList</param>
/// <param name="dataCount">Num of bits for datacodewords without terminator</param>
/// <param name="numTotalDataCodewords">Total number of datacodewords for specific version.
/// Receive it under Version/VersionTable</param>
internal static void TerminateBites(this BitList baseList, int dataCount, int numTotalDataCodewords)
{
int numTotalDataBits = numTotalDataCodewords << 3;
int numDataBits = dataCount;
int numFillerBits = numTotalDataBits - numDataBits;
int numBitsNeedForLastByte = numFillerBits & 0x7;
int numFillerBytes = numFillerBits >> 3;
int numFillerBits = numTotalDataBits - numDataBits;
int numBitsNeedForLastByte = numFillerBits & 0x7;
int numFillerBytes = numFillerBits >> 3;
// BitList result = new BitList();
if (numBitsNeedForLastByte >= QRCodeConstantVariable.TerminatorLength)
{
baseList.TerminatorPadding(numBitsNeedForLastByte);
baseList.PadeCodewords(numFillerBytes);
}
else if (numFillerBytes == 0)
{
baseList.TerminatorPadding(numBitsNeedForLastByte);
}
else if (numFillerBytes > 0)
{
baseList.TerminatorPadding(numBitsNeedForLastByte + NumBitsForByte);
baseList.PadeCodewords(numFillerBytes - 1);
}
// BitList result = new BitList();
if (numBitsNeedForLastByte >= QRCodeConstantVariable.TerminatorLength)
{
baseList.TerminatorPadding(numBitsNeedForLastByte);
baseList.PadeCodewords(numFillerBytes);
}
else if (numFillerBytes == 0)
{
baseList.TerminatorPadding(numBitsNeedForLastByte);
}
else if (numFillerBytes > 0)
{
baseList.TerminatorPadding(numBitsNeedForLastByte + NumBitsForByte);
baseList.PadeCodewords(numFillerBytes - 1);
}
if (baseList.Count != numTotalDataBits)
{
throw new ArgumentException(
$"Generate terminator and Padding fail. Num of bits need: {numFillerBytes}. Actual length: {baseList.Count - numDataBits}");
}
}
if (baseList.Count != numTotalDataBits)
{
throw new ArgumentException(
$"Generate terminator and Padding fail. Num of bits need: {numFillerBytes}. Actual length: {baseList.Count - numDataBits}");
}
}
private static void PadeCodewords(this BitList mainList, int numOfPadeCodewords)
{
if (numOfPadeCodewords < 0)
{
throw new ArgumentException("Num of pade codewords is less than Zero");
}
private static void PadeCodewords(this BitList mainList, int numOfPadeCodewords)
{
if (numOfPadeCodewords < 0)
{
throw new ArgumentException("Num of pade codewords is less than Zero");
}
for (int numOfP = 1; numOfP <= numOfPadeCodewords; numOfP++)
{
if (numOfP % 2 == 1)
{
mainList.Add(QRCodeConstantVariable.PadeCodewordsOdd, NumBitsForByte);
}
else
{
mainList.Add(QRCodeConstantVariable.PadeCodewordsEven, NumBitsForByte);
}
}
}
for (int numOfP = 1; numOfP <= numOfPadeCodewords; numOfP++)
{
if (numOfP % 2 == 1)
{
mainList.Add(QRCodeConstantVariable.PadeCodewordsOdd, NumBitsForByte);
}
else
{
mainList.Add(QRCodeConstantVariable.PadeCodewordsEven, NumBitsForByte);
}
}
}
private static void TerminatorPadding(this BitList mainList, int numBits) => mainList.Add(QRCodeConstantVariable.TerminatorNPaddingBit, numBits);
}
private static void TerminatorPadding(this BitList mainList, int numBits) => mainList.Add(QRCodeConstantVariable.TerminatorNPaddingBit, numBits);
}
@@ -1,48 +1,46 @@
using System;
namespace Gma.QrCodeNet.Encoding;
public class TriStateMatrix : BitMatrixBase
{
public TriStateMatrix(int width) : base(width, new bool[width, width])
{
StateMatrix = new StateMatrix(width);
}
public TriStateMatrix(int width) : base(width, new bool[width, width])
{
StateMatrix = new StateMatrix(width);
}
internal TriStateMatrix(bool[,] internalArray) : base(internalArray)
{
StateMatrix = new StateMatrix(internalArray.GetLength(0));
}
internal TriStateMatrix(bool[,] internalArray) : base(internalArray)
{
StateMatrix = new StateMatrix(internalArray.GetLength(0));
}
private StateMatrix StateMatrix { get; }
private StateMatrix StateMatrix { get; }
public override bool this[int i, int j]
{
get => InternalArray[i, j];
set
{
if (MStatus(i, j) is MatrixStatus.None or MatrixStatus.NoMask)
{
throw new InvalidOperationException($"The value of cell [{i}, {j}] is not set or is Stencil.");
}
InternalArray[i, j] = value;
}
}
public override bool this[int i, int j]
{
get => InternalArray[i, j];
set
{
if (MStatus(i, j) is MatrixStatus.None or MatrixStatus.NoMask)
{
throw new InvalidOperationException($"The value of cell [{i}, {j}] is not set or is Stencil.");
}
InternalArray[i, j] = value;
}
}
public bool this[int i, int j, MatrixStatus mstatus]
{
set
{
StateMatrix[i, j] = mstatus;
InternalArray[i, j] = value;
}
}
public bool this[int i, int j, MatrixStatus mstatus]
{
set
{
StateMatrix[i, j] = mstatus;
InternalArray[i, j] = value;
}
}
public override int Height => Width;
public override int Height => Width;
public override int Width => base.Width;
public override int Width => base.Width;
internal MatrixStatus MStatus(int i, int j) => StateMatrix[i, j];
internal MatrixStatus MStatus(int i, int j) => StateMatrix[i, j];
internal MatrixStatus MStatus(MatrixPoint point) => MStatus(point.X, point.Y);
}
internal MatrixStatus MStatus(MatrixPoint point) => MStatus(point.X, point.Y);
}
@@ -2,33 +2,33 @@ namespace Gma.QrCodeNet.Encoding;
public struct VersionDetail
{
internal VersionDetail(int version, int numTotalBytes, int numDataBytes, int numECBlocks)
: this()
{
Version = version;
NumTotalBytes = numTotalBytes;
NumDataBytes = numDataBytes;
NumECBlocks = numECBlocks;
}
internal VersionDetail(int version, int numTotalBytes, int numDataBytes, int numECBlocks)
: this()
{
Version = version;
NumTotalBytes = numTotalBytes;
NumDataBytes = numDataBytes;
NumECBlocks = numECBlocks;
}
internal int Version { get; private set; }
internal int NumTotalBytes { get; private set; }
internal int NumDataBytes { get; private set; }
internal int NumECBlocks { get; private set; }
internal int Version { get; private set; }
internal int NumTotalBytes { get; private set; }
internal int NumDataBytes { get; private set; }
internal int NumECBlocks { get; private set; }
internal int MatrixWidth => Width(Version);
internal int MatrixWidth => Width(Version);
internal int ECBlockGroup1 => NumECBlocks - ECBlockGroup2;
internal int ECBlockGroup1 => NumECBlocks - ECBlockGroup2;
internal int ECBlockGroup2 => NumTotalBytes % NumECBlocks;
internal int ECBlockGroup2 => NumTotalBytes % NumECBlocks;
internal int NumDataBytesGroup1 => NumDataBytes / NumECBlocks;
internal int NumDataBytesGroup1 => NumDataBytes / NumECBlocks;
internal int NumDataBytesGroup2 => NumDataBytesGroup1 + 1;
internal int NumDataBytesGroup2 => NumDataBytesGroup1 + 1;
internal int NumECBytesPerBlock => (NumTotalBytes - NumDataBytes) / NumECBlocks;
internal int NumECBytesPerBlock => (NumTotalBytes - NumDataBytes) / NumECBlocks;
internal static int Width(int version) => 17 + (4 * version);
internal static int Width(int version) => 17 + (4 * version);
public override string ToString() => $"{Version};{NumTotalBytes};{NumDataBytes};{NumECBlocks}";
}
public override string ToString() => $"{Version};{NumTotalBytes};{NumDataBytes};{NumECBlocks}";
}
@@ -2,14 +2,14 @@ namespace Gma.QrCodeNet.Encoding.Versions;
internal struct ErrorCorrectionBlock
{
internal ErrorCorrectionBlock(int numErrorCorrectionBlock, int numDataCodewards)
: this()
{
NumErrorCorrectionBlock = numErrorCorrectionBlock;
NumDataCodewords = numDataCodewards;
}
internal ErrorCorrectionBlock(int numErrorCorrectionBlock, int numDataCodewards)
: this()
{
NumErrorCorrectionBlock = numErrorCorrectionBlock;
NumDataCodewords = numDataCodewards;
}
internal int NumErrorCorrectionBlock { get; private set; }
internal int NumErrorCorrectionBlock { get; private set; }
internal int NumDataCodewords { get; private set; }
}
internal int NumDataCodewords { get; private set; }
}
@@ -1,55 +1,53 @@
using System;
namespace Gma.QrCodeNet.Encoding.Versions;
internal struct ErrorCorrectionBlocks
{
internal ErrorCorrectionBlocks(int numErrorCorrectionCodewords, ErrorCorrectionBlock ecBlock)
: this()
{
NumErrorCorrectionCodewards = numErrorCorrectionCodewords;
ECBlock = new ErrorCorrectionBlock[] { ecBlock };
internal ErrorCorrectionBlocks(int numErrorCorrectionCodewords, ErrorCorrectionBlock ecBlock)
: this()
{
NumErrorCorrectionCodewards = numErrorCorrectionCodewords;
ECBlock = new ErrorCorrectionBlock[] { ecBlock };
Initialize();
}
Initialize();
}
internal ErrorCorrectionBlocks(int numErrorCorrectionCodewords, ErrorCorrectionBlock ecBlock1, ErrorCorrectionBlock ecBlock2)
: this()
{
NumErrorCorrectionCodewards = numErrorCorrectionCodewords;
ECBlock = new ErrorCorrectionBlock[] { ecBlock1, ecBlock2 };
internal ErrorCorrectionBlocks(int numErrorCorrectionCodewords, ErrorCorrectionBlock ecBlock1, ErrorCorrectionBlock ecBlock2)
: this()
{
NumErrorCorrectionCodewards = numErrorCorrectionCodewords;
ECBlock = new ErrorCorrectionBlock[] { ecBlock1, ecBlock2 };
Initialize();
}
Initialize();
}
internal int NumErrorCorrectionCodewards { get; private set; }
internal int NumErrorCorrectionCodewards { get; private set; }
internal int NumBlocks { get; private set; }
internal int NumBlocks { get; private set; }
internal int ErrorCorrectionCodewordsPerBlock { get; private set; }
internal int ErrorCorrectionCodewordsPerBlock { get; private set; }
private ErrorCorrectionBlock[] ECBlock { get; }
private ErrorCorrectionBlock[] ECBlock { get; }
/// <summary>
/// Get Error Correction Blocks
/// </summary>
internal ErrorCorrectionBlock[] GetECBlocks() => ECBlock;
/// <summary>
/// Get Error Correction Blocks
/// </summary>
internal ErrorCorrectionBlock[] GetECBlocks() => ECBlock;
/// <summary>
/// Initialize for NumBlocks and ErrorCorrectionCodewordsPerBlock
/// </summary>
private void Initialize()
/// <summary>
/// Initialize for NumBlocks and ErrorCorrectionCodewordsPerBlock
/// </summary>
private void Initialize()
{
if (ECBlock == null)
throw new ArgumentNullException(nameof(ECBlock));
NumBlocks = 0;
int blockLength = ECBlock.Length;
for (int i = 0; i < blockLength; i++)
{
NumBlocks += ECBlock[i].NumErrorCorrectionBlock;
}
int blockLength = ECBlock.Length;
for (int i = 0; i < blockLength; i++)
{
NumBlocks += ECBlock[i].NumErrorCorrectionBlock;
}
ErrorCorrectionCodewordsPerBlock = NumErrorCorrectionCodewards / NumBlocks;
}
}
ErrorCorrectionCodewordsPerBlock = NumErrorCorrectionCodewards / NumBlocks;
}
}
@@ -1,35 +1,33 @@
using System;
namespace Gma.QrCodeNet.Encoding.Versions;
internal struct QRCodeVersion
{
internal QRCodeVersion(int versionNum, int totalCodewords, ErrorCorrectionBlocks ecblocksL, ErrorCorrectionBlocks ecblocksM, ErrorCorrectionBlocks ecblocksQ, ErrorCorrectionBlocks ecblocksH)
: this()
{
VersionNum = versionNum;
TotalCodewords = totalCodewords;
ECBlocks = new ErrorCorrectionBlocks[] { ecblocksL, ecblocksM, ecblocksQ, ecblocksH };
DimensionForVersion = 17 + (versionNum * 4);
}
internal QRCodeVersion(int versionNum, int totalCodewords, ErrorCorrectionBlocks ecblocksL, ErrorCorrectionBlocks ecblocksM, ErrorCorrectionBlocks ecblocksQ, ErrorCorrectionBlocks ecblocksH)
: this()
{
VersionNum = versionNum;
TotalCodewords = totalCodewords;
ECBlocks = new ErrorCorrectionBlocks[] { ecblocksL, ecblocksM, ecblocksQ, ecblocksH };
DimensionForVersion = 17 + (versionNum * 4);
}
internal int VersionNum { get; private set; }
internal int VersionNum { get; private set; }
internal int TotalCodewords { get; private set; }
internal int TotalCodewords { get; private set; }
internal int DimensionForVersion { get; private set; }
internal int DimensionForVersion { get; private set; }
private ErrorCorrectionBlocks[] ECBlocks { get; }
private ErrorCorrectionBlocks[] ECBlocks { get; }
internal ErrorCorrectionBlocks GetECBlocksByLevel(ErrorCorrectionLevel eCLevel)
{
return eCLevel switch
{
ErrorCorrectionLevel.L => ECBlocks[0],
ErrorCorrectionLevel.M => ECBlocks[1],
ErrorCorrectionLevel.Q => ECBlocks[2],
ErrorCorrectionLevel.H => ECBlocks[3],
_ => throw new ArgumentOutOfRangeException(nameof(eCLevel))
};
}
}
internal ErrorCorrectionBlocks GetECBlocksByLevel(ErrorCorrectionLevel eCLevel)
{
return eCLevel switch
{
ErrorCorrectionLevel.L => ECBlocks[0],
ErrorCorrectionLevel.M => ECBlocks[1],
ErrorCorrectionLevel.Q => ECBlocks[2],
ErrorCorrectionLevel.H => ECBlocks[3],
_ => throw new ArgumentOutOfRangeException(nameof(eCLevel))
};
}
}
@@ -1,144 +1,143 @@
using System;
using Gma.QrCodeNet.Encoding.DataEncodation;
namespace Gma.QrCodeNet.Encoding.Versions;
internal static class VersionControl
{
private const int NumBitsModeIndicator = 4;
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
private const int NumBitsModeIndicator = 4;
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
private static readonly int[] VERSION_GROUP = new int[] { 9, 26, 40 };
private static readonly int[] VERSION_GROUP = new int[] { 9, 26, 40 };
/// <summary>
/// Determine which version to use
/// </summary>
/// <param name="dataBitsLength">Number of bits for encoded content</param>
/// <param name="encodingName">Encoding name for EightBitByte</param>
/// <returns>VersionDetail and ECI</returns>
internal static VersionControlStruct InitialSetup(int dataBitsLength, ErrorCorrectionLevel level, string encodingName)
{
int totalDataBits = dataBitsLength;
/// <summary>
/// Determine which version to use
/// </summary>
/// <param name="dataBitsLength">Number of bits for encoded content</param>
/// <param name="encodingName">Encoding name for EightBitByte</param>
/// <returns>VersionDetail and ECI</returns>
internal static VersionControlStruct InitialSetup(int dataBitsLength, ErrorCorrectionLevel level, string encodingName)
{
int totalDataBits = dataBitsLength;
bool containECI = false;
bool containECI = false;
BitList eciHeader = new();
BitList eciHeader = new();
if (encodingName is not DefaultEncoding and not QRCodeConstantVariable.UTF8Encoding)
{
ECISet eciSet = new(ECISet.AppendOption.NameToValue);
int eciValue = eciSet.GetECIValueByName(encodingName);
if (encodingName is not DefaultEncoding and not QRCodeConstantVariable.UTF8Encoding)
{
ECISet eciSet = new(ECISet.AppendOption.NameToValue);
int eciValue = eciSet.GetECIValueByName(encodingName);
totalDataBits += ECISet.NumOfECIHeaderBits(eciValue);
eciHeader = eciSet.GetECIHeader(encodingName);
containECI = true;
}
totalDataBits += ECISet.NumOfECIHeaderBits(eciValue);
eciHeader = eciSet.GetECIHeader(encodingName);
containECI = true;
}
// Determine which version group it belong to
int searchGroup = DynamicSearchIndicator(totalDataBits, level);
// Determine which version group it belong to
int searchGroup = DynamicSearchIndicator(totalDataBits, level);
int[] charCountIndicator = CharCountIndicatorTable.GetCharCountIndicatorSet();
int[] charCountIndicator = CharCountIndicatorTable.GetCharCountIndicatorSet();
totalDataBits += (NumBitsModeIndicator + charCountIndicator[searchGroup]);
totalDataBits += (NumBitsModeIndicator + charCountIndicator[searchGroup]);
int lowerSearchBoundary = searchGroup == 0 ? 1 : (VERSION_GROUP[searchGroup - 1] + 1);
int higherSearchBoundary = VERSION_GROUP[searchGroup];
int lowerSearchBoundary = searchGroup == 0 ? 1 : (VERSION_GROUP[searchGroup - 1] + 1);
int higherSearchBoundary = VERSION_GROUP[searchGroup];
// Binary search to find proper version
int versionNum = BinarySearch(totalDataBits, level, lowerSearchBoundary, higherSearchBoundary);
// Binary search to find proper version
int versionNum = BinarySearch(totalDataBits, level, lowerSearchBoundary, higherSearchBoundary);
VersionControlStruct vcStruct = FillVCStruct(versionNum, level);
VersionControlStruct vcStruct = FillVCStruct(versionNum, level);
vcStruct.IsContainECI = containECI;
vcStruct.IsContainECI = containECI;
vcStruct.ECIHeader = eciHeader;
vcStruct.ECIHeader = eciHeader;
return vcStruct;
}
return vcStruct;
}
private static VersionControlStruct FillVCStruct(int versionNum, ErrorCorrectionLevel level)
{
if (versionNum is < 1 or > 40)
{
throw new InvalidOperationException($"Unexpected version number: {versionNum}");
}
private static VersionControlStruct FillVCStruct(int versionNum, ErrorCorrectionLevel level)
{
if (versionNum is < 1 or > 40)
{
throw new InvalidOperationException($"Unexpected version number: {versionNum}");
}
VersionControlStruct vcStruct = new();
VersionControlStruct vcStruct = new();
int version = versionNum;
int version = versionNum;
QRCodeVersion versionData = VersionTable.GetVersionByNum(versionNum);
QRCodeVersion versionData = VersionTable.GetVersionByNum(versionNum);
int numTotalBytes = versionData.TotalCodewords;
int numTotalBytes = versionData.TotalCodewords;
ErrorCorrectionBlocks ecBlocks = versionData.GetECBlocksByLevel(level);
int numDataBytes = numTotalBytes - ecBlocks.NumErrorCorrectionCodewards;
int numECBlocks = ecBlocks.NumBlocks;
ErrorCorrectionBlocks ecBlocks = versionData.GetECBlocksByLevel(level);
int numDataBytes = numTotalBytes - ecBlocks.NumErrorCorrectionCodewards;
int numECBlocks = ecBlocks.NumBlocks;
VersionDetail vcDetail = new(version, numTotalBytes, numDataBytes, numECBlocks);
VersionDetail vcDetail = new(version, numTotalBytes, numDataBytes, numECBlocks);
vcStruct.VersionDetail = vcDetail;
return vcStruct;
}
vcStruct.VersionDetail = vcDetail;
return vcStruct;
}
/// <summary>
/// Decide which version group it belong to
/// </summary>
/// <param name="numBits">Number of bits for bitlist where it contain DataBits encode from input content and ECI header</param>
/// <param name="level">Error correction level</param>
/// <returns>Version group index for VERSION_GROUP</returns>
private static int DynamicSearchIndicator(int numBits, ErrorCorrectionLevel level)
{
int[] charCountIndicator = CharCountIndicatorTable.GetCharCountIndicatorSet();
int loopLength = VERSION_GROUP.Length;
for (int i = 0; i < loopLength; i++)
{
int totalBits = numBits + NumBitsModeIndicator + charCountIndicator[i];
/// <summary>
/// Decide which version group it belong to
/// </summary>
/// <param name="numBits">Number of bits for bitlist where it contain DataBits encode from input content and ECI header</param>
/// <param name="level">Error correction level</param>
/// <returns>Version group index for VERSION_GROUP</returns>
private static int DynamicSearchIndicator(int numBits, ErrorCorrectionLevel level)
{
int[] charCountIndicator = CharCountIndicatorTable.GetCharCountIndicatorSet();
int loopLength = VERSION_GROUP.Length;
for (int i = 0; i < loopLength; i++)
{
int totalBits = numBits + NumBitsModeIndicator + charCountIndicator[i];
QRCodeVersion version = VersionTable.GetVersionByNum(VERSION_GROUP[i]);
int numECCodewords = version.GetECBlocksByLevel(level).NumErrorCorrectionCodewards;
QRCodeVersion version = VersionTable.GetVersionByNum(VERSION_GROUP[i]);
int numECCodewords = version.GetECBlocksByLevel(level).NumErrorCorrectionCodewards;
int dataCodewords = version.TotalCodewords - numECCodewords;
int dataCodewords = version.TotalCodewords - numECCodewords;
if (totalBits <= dataCodewords * 8)
{
return i;
}
}
if (totalBits <= dataCodewords * 8)
{
return i;
}
}
throw new InputOutOfBoundaryException($"QRCode do not have enough space for {(numBits + NumBitsModeIndicator + charCountIndicator[2])} bits");
}
throw new InputOutOfBoundaryException($"QRCode do not have enough space for {(numBits + NumBitsModeIndicator + charCountIndicator[2])} bits");
}
/// <summary>
/// Use number of data bits(header + eci header + data bits from EncoderBase) to search for proper version to use
/// between min and max boundary.
/// Boundary define by DynamicSearchIndicator method.
/// </summary>
private static int BinarySearch(int numDataBits, ErrorCorrectionLevel level, int lowerVersionNum, int higherVersionNum)
{
int middleVersionNumber;
/// <summary>
/// Use number of data bits(header + eci header + data bits from EncoderBase) to search for proper version to use
/// between min and max boundary.
/// Boundary define by DynamicSearchIndicator method.
/// </summary>
private static int BinarySearch(int numDataBits, ErrorCorrectionLevel level, int lowerVersionNum, int higherVersionNum)
{
int middleVersionNumber;
while (lowerVersionNum <= higherVersionNum)
{
middleVersionNumber = (lowerVersionNum + higherVersionNum) / 2;
QRCodeVersion version = VersionTable.GetVersionByNum(middleVersionNumber);
int numECCodewords = version.GetECBlocksByLevel(level).NumErrorCorrectionCodewards;
int dataCodewords = version.TotalCodewords - numECCodewords;
while (lowerVersionNum <= higherVersionNum)
{
middleVersionNumber = (lowerVersionNum + higherVersionNum) / 2;
QRCodeVersion version = VersionTable.GetVersionByNum(middleVersionNumber);
int numECCodewords = version.GetECBlocksByLevel(level).NumErrorCorrectionCodewards;
int dataCodewords = version.TotalCodewords - numECCodewords;
if (dataCodewords << 3 == numDataBits)
{
return middleVersionNumber;
}
if (dataCodewords << 3 == numDataBits)
{
return middleVersionNumber;
}
if (dataCodewords << 3 > numDataBits)
{
higherVersionNum = middleVersionNumber - 1;
}
else
{
lowerVersionNum = middleVersionNumber + 1;
}
}
return lowerVersionNum;
}
}
if (dataCodewords << 3 > numDataBits)
{
higherVersionNum = middleVersionNumber - 1;
}
else
{
lowerVersionNum = middleVersionNumber + 1;
}
}
return lowerVersionNum;
}
}
@@ -2,7 +2,7 @@ namespace Gma.QrCodeNet.Encoding.Versions;
internal struct VersionControlStruct
{
internal VersionDetail VersionDetail { get; set; }
internal bool IsContainECI { get; set; }
internal BitList ECIHeader { get; set; }
}
internal VersionDetail VersionDetail { get; set; }
internal bool IsContainECI { get; set; }
internal BitList ECIHeader { get; set; }
}
@@ -1,317 +1,315 @@
using System;
namespace Gma.QrCodeNet.Encoding.Versions;
public static class VersionTable
{
private static readonly QRCodeVersion[] Version = Initialize();
private static readonly QRCodeVersion[] Version = Initialize();
internal static QRCodeVersion GetVersionByNum(int versionNum)
{
if (versionNum is < QRCodeConstantVariable.MinVersion or > QRCodeConstantVariable.MaxVersion)
{
throw new InvalidOperationException($"Unexpected version number: {versionNum}.");
}
internal static QRCodeVersion GetVersionByNum(int versionNum)
{
if (versionNum is < QRCodeConstantVariable.MinVersion or > QRCodeConstantVariable.MaxVersion)
{
throw new InvalidOperationException($"Unexpected version number: {versionNum}.");
}
return Version[versionNum - 1];
}
return Version[versionNum - 1];
}
internal static QRCodeVersion GetVersionByWidth(int matrixWidth)
{
if ((matrixWidth - 17) % 4 != 0)
{
throw new ArgumentException("Incorrect matrix width.");
}
else
{
return GetVersionByNum((matrixWidth - 17) / 4);
}
}
internal static QRCodeVersion GetVersionByWidth(int matrixWidth)
{
if ((matrixWidth - 17) % 4 != 0)
{
throw new ArgumentException("Incorrect matrix width.");
}
else
{
return GetVersionByNum((matrixWidth - 17) / 4);
}
}
private static QRCodeVersion[] Initialize()
{
return new QRCodeVersion[]
{
new QRCodeVersion(
1,
26,
new ErrorCorrectionBlocks(7, new ErrorCorrectionBlock(1, 19)),
new ErrorCorrectionBlocks(10, new ErrorCorrectionBlock(1, 16)),
new ErrorCorrectionBlocks(13, new ErrorCorrectionBlock(1, 13)),
new ErrorCorrectionBlocks(17, new ErrorCorrectionBlock(1, 9))),
new QRCodeVersion(
2,
44,
new ErrorCorrectionBlocks(10, new ErrorCorrectionBlock(1, 34)),
new ErrorCorrectionBlocks(16, new ErrorCorrectionBlock(1, 28)),
new ErrorCorrectionBlocks(22, new ErrorCorrectionBlock(1, 22)),
new ErrorCorrectionBlocks(28, new ErrorCorrectionBlock(1, 16))),
new QRCodeVersion(
3,
70,
new ErrorCorrectionBlocks(15, new ErrorCorrectionBlock(1, 55)),
new ErrorCorrectionBlocks(26, new ErrorCorrectionBlock(1, 44)),
new ErrorCorrectionBlocks(36, new ErrorCorrectionBlock(2, 17)),
new ErrorCorrectionBlocks(44, new ErrorCorrectionBlock(2, 13))),
new QRCodeVersion(
4,
100,
new ErrorCorrectionBlocks(20, new ErrorCorrectionBlock(1, 80)),
new ErrorCorrectionBlocks(36, new ErrorCorrectionBlock(2, 32)),
new ErrorCorrectionBlocks(52, new ErrorCorrectionBlock(2, 24)),
new ErrorCorrectionBlocks(64, new ErrorCorrectionBlock(4, 9))),
new QRCodeVersion(
5,
134,
new ErrorCorrectionBlocks(26, new ErrorCorrectionBlock(1, 108)),
new ErrorCorrectionBlocks(48, new ErrorCorrectionBlock(2, 43)),
new ErrorCorrectionBlocks(72, new ErrorCorrectionBlock(2, 15), new ErrorCorrectionBlock(2, 16)),
new ErrorCorrectionBlocks(88, new ErrorCorrectionBlock(2, 11), new ErrorCorrectionBlock(2, 12))),
new QRCodeVersion(
6,
172,
new ErrorCorrectionBlocks(36, new ErrorCorrectionBlock(2, 68)),
new ErrorCorrectionBlocks(64, new ErrorCorrectionBlock(4, 27)),
new ErrorCorrectionBlocks(96, new ErrorCorrectionBlock(4, 19)),
new ErrorCorrectionBlocks(112, new ErrorCorrectionBlock(4, 15))),
new QRCodeVersion(
7,
196,
new ErrorCorrectionBlocks(40, new ErrorCorrectionBlock(2, 78)),
new ErrorCorrectionBlocks(72, new ErrorCorrectionBlock(4, 31)),
new ErrorCorrectionBlocks(108, new ErrorCorrectionBlock(2, 14), new ErrorCorrectionBlock(4, 15)),
new ErrorCorrectionBlocks(130, new ErrorCorrectionBlock(4, 13), new ErrorCorrectionBlock(1, 14))),
new QRCodeVersion(
8,
242,
new ErrorCorrectionBlocks(48, new ErrorCorrectionBlock(2, 97)),
new ErrorCorrectionBlocks(88, new ErrorCorrectionBlock(2, 38), new ErrorCorrectionBlock(2, 39)),
new ErrorCorrectionBlocks(132, new ErrorCorrectionBlock(4, 18), new ErrorCorrectionBlock(2, 19)),
new ErrorCorrectionBlocks(156, new ErrorCorrectionBlock(4, 14), new ErrorCorrectionBlock(2, 15))),
new QRCodeVersion(
9,
292,
new ErrorCorrectionBlocks(60, new ErrorCorrectionBlock(2, 116)),
new ErrorCorrectionBlocks(110, new ErrorCorrectionBlock(3, 36), new ErrorCorrectionBlock(2, 37)),
new ErrorCorrectionBlocks(160, new ErrorCorrectionBlock(4, 16), new ErrorCorrectionBlock(4, 17)),
new ErrorCorrectionBlocks(192, new ErrorCorrectionBlock(4, 12), new ErrorCorrectionBlock(4, 13))),
new QRCodeVersion(
10,
346,
new ErrorCorrectionBlocks(72, new ErrorCorrectionBlock(2, 68), new ErrorCorrectionBlock(2, 69)),
new ErrorCorrectionBlocks(130, new ErrorCorrectionBlock(4, 43), new ErrorCorrectionBlock(1, 44)),
new ErrorCorrectionBlocks(192, new ErrorCorrectionBlock(6, 19), new ErrorCorrectionBlock(2, 20)),
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(6, 15), new ErrorCorrectionBlock(2, 16))),
new QRCodeVersion(
11,
404,
new ErrorCorrectionBlocks(80, new ErrorCorrectionBlock(4, 81)),
new ErrorCorrectionBlocks(150, new ErrorCorrectionBlock(1, 50), new ErrorCorrectionBlock(4, 51)),
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(4, 22), new ErrorCorrectionBlock(4, 23)),
new ErrorCorrectionBlocks(264, new ErrorCorrectionBlock(3, 12), new ErrorCorrectionBlock(8, 13))),
new QRCodeVersion(
12,
466,
new ErrorCorrectionBlocks(96, new ErrorCorrectionBlock(2, 92), new ErrorCorrectionBlock(2, 93)),
new ErrorCorrectionBlocks(176, new ErrorCorrectionBlock(6, 36), new ErrorCorrectionBlock(2, 37)),
new ErrorCorrectionBlocks(260, new ErrorCorrectionBlock(4, 20), new ErrorCorrectionBlock(6, 21)),
new ErrorCorrectionBlocks(308, new ErrorCorrectionBlock(7, 14), new ErrorCorrectionBlock(4, 15))),
new QRCodeVersion(
13,
532,
new ErrorCorrectionBlocks(104, new ErrorCorrectionBlock(4, 107)),
new ErrorCorrectionBlocks(198, new ErrorCorrectionBlock(8, 37), new ErrorCorrectionBlock(1, 38)),
new ErrorCorrectionBlocks(288, new ErrorCorrectionBlock(8, 20), new ErrorCorrectionBlock(4, 21)),
new ErrorCorrectionBlocks(352, new ErrorCorrectionBlock(12, 11), new ErrorCorrectionBlock(4, 12))),
new QRCodeVersion(
14,
581,
new ErrorCorrectionBlocks(120, new ErrorCorrectionBlock(3, 115), new ErrorCorrectionBlock(1, 116)),
new ErrorCorrectionBlocks(216, new ErrorCorrectionBlock(4, 40), new ErrorCorrectionBlock(5, 41)),
new ErrorCorrectionBlocks(320, new ErrorCorrectionBlock(11, 16), new ErrorCorrectionBlock(5, 17)),
new ErrorCorrectionBlocks(384, new ErrorCorrectionBlock(11, 12), new ErrorCorrectionBlock(5, 13))),
new QRCodeVersion(
15,
655,
new ErrorCorrectionBlocks(132, new ErrorCorrectionBlock(5, 87), new ErrorCorrectionBlock(1, 88)),
new ErrorCorrectionBlocks(240, new ErrorCorrectionBlock(5, 41), new ErrorCorrectionBlock(5, 42)),
new ErrorCorrectionBlocks(360, new ErrorCorrectionBlock(5, 24), new ErrorCorrectionBlock(7, 25)),
new ErrorCorrectionBlocks(432, new ErrorCorrectionBlock(11, 12), new ErrorCorrectionBlock(7, 13))),
new QRCodeVersion(
16,
733,
new ErrorCorrectionBlocks(144, new ErrorCorrectionBlock(5, 98), new ErrorCorrectionBlock(1, 99)),
new ErrorCorrectionBlocks(280, new ErrorCorrectionBlock(7, 45), new ErrorCorrectionBlock(3, 46)),
new ErrorCorrectionBlocks(408, new ErrorCorrectionBlock(15, 19), new ErrorCorrectionBlock(2, 20)),
new ErrorCorrectionBlocks(480, new ErrorCorrectionBlock(3, 15), new ErrorCorrectionBlock(13, 16))),
new QRCodeVersion(
17,
815,
new ErrorCorrectionBlocks(168, new ErrorCorrectionBlock(1, 107), new ErrorCorrectionBlock(5, 108)),
new ErrorCorrectionBlocks(308, new ErrorCorrectionBlock(10, 46), new ErrorCorrectionBlock(1, 47)),
new ErrorCorrectionBlocks(448, new ErrorCorrectionBlock(1, 22), new ErrorCorrectionBlock(15, 23)),
new ErrorCorrectionBlocks(532, new ErrorCorrectionBlock(2, 14), new ErrorCorrectionBlock(17, 15))),
new QRCodeVersion(
18,
901,
new ErrorCorrectionBlocks(180, new ErrorCorrectionBlock(5, 120), new ErrorCorrectionBlock(1, 121)),
new ErrorCorrectionBlocks(338, new ErrorCorrectionBlock(9, 43), new ErrorCorrectionBlock(4, 44)),
new ErrorCorrectionBlocks(504, new ErrorCorrectionBlock(17, 22), new ErrorCorrectionBlock(1, 23)),
new ErrorCorrectionBlocks(588, new ErrorCorrectionBlock(2, 14), new ErrorCorrectionBlock(19, 15))),
new QRCodeVersion(
19,
991,
new ErrorCorrectionBlocks(196, new ErrorCorrectionBlock(3, 113), new ErrorCorrectionBlock(4, 114)),
new ErrorCorrectionBlocks(364, new ErrorCorrectionBlock(3, 44), new ErrorCorrectionBlock(11, 45)),
new ErrorCorrectionBlocks(546, new ErrorCorrectionBlock(17, 21), new ErrorCorrectionBlock(4, 22)),
new ErrorCorrectionBlocks(650, new ErrorCorrectionBlock(9, 13), new ErrorCorrectionBlock(16, 14))),
new QRCodeVersion(
20,
1085,
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(3, 107), new ErrorCorrectionBlock(5, 108)),
new ErrorCorrectionBlocks(416, new ErrorCorrectionBlock(3, 41), new ErrorCorrectionBlock(13, 42)),
new ErrorCorrectionBlocks(600, new ErrorCorrectionBlock(15, 24), new ErrorCorrectionBlock(5, 25)),
new ErrorCorrectionBlocks(700, new ErrorCorrectionBlock(15, 15), new ErrorCorrectionBlock(10, 16))),
new QRCodeVersion(
21,
1156,
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(4, 116), new ErrorCorrectionBlock(4, 117)),
new ErrorCorrectionBlocks(442, new ErrorCorrectionBlock(17, 42)),
new ErrorCorrectionBlocks(644, new ErrorCorrectionBlock(17, 22), new ErrorCorrectionBlock(6, 23)),
new ErrorCorrectionBlocks(750, new ErrorCorrectionBlock(19, 16), new ErrorCorrectionBlock(6, 17))),
new QRCodeVersion(
22,
1258,
new ErrorCorrectionBlocks(252, new ErrorCorrectionBlock(2, 111), new ErrorCorrectionBlock(7, 112)),
new ErrorCorrectionBlocks(476, new ErrorCorrectionBlock(17, 46)),
new ErrorCorrectionBlocks(690, new ErrorCorrectionBlock(7, 24), new ErrorCorrectionBlock(16, 25)),
new ErrorCorrectionBlocks(816, new ErrorCorrectionBlock(34, 13))),
new QRCodeVersion(
23,
1364,
new ErrorCorrectionBlocks(270, new ErrorCorrectionBlock(4, 121), new ErrorCorrectionBlock(5, 122)),
new ErrorCorrectionBlocks(504, new ErrorCorrectionBlock(4, 47), new ErrorCorrectionBlock(14, 48)),
new ErrorCorrectionBlocks(750, new ErrorCorrectionBlock(11, 24), new ErrorCorrectionBlock(14, 25)),
new ErrorCorrectionBlocks(900, new ErrorCorrectionBlock(16, 15), new ErrorCorrectionBlock(14, 16))),
new QRCodeVersion(
24,
1474,
new ErrorCorrectionBlocks(300, new ErrorCorrectionBlock(6, 117), new ErrorCorrectionBlock(4, 118)),
new ErrorCorrectionBlocks(560, new ErrorCorrectionBlock(6, 45), new ErrorCorrectionBlock(14, 46)),
new ErrorCorrectionBlocks(810, new ErrorCorrectionBlock(11, 24), new ErrorCorrectionBlock(16, 25)),
new ErrorCorrectionBlocks(960, new ErrorCorrectionBlock(30, 16), new ErrorCorrectionBlock(2, 17))),
new QRCodeVersion(
25,
1588,
new ErrorCorrectionBlocks(312, new ErrorCorrectionBlock(8, 106), new ErrorCorrectionBlock(4, 107)),
new ErrorCorrectionBlocks(588, new ErrorCorrectionBlock(8, 47), new ErrorCorrectionBlock(13, 48)),
new ErrorCorrectionBlocks(870, new ErrorCorrectionBlock(7, 24), new ErrorCorrectionBlock(22, 25)),
new ErrorCorrectionBlocks(1050, new ErrorCorrectionBlock(22, 15), new ErrorCorrectionBlock(13, 16))),
new QRCodeVersion(
26,
1706,
new ErrorCorrectionBlocks(336, new ErrorCorrectionBlock(10, 114), new ErrorCorrectionBlock(2, 115)),
new ErrorCorrectionBlocks(644, new ErrorCorrectionBlock(19, 46), new ErrorCorrectionBlock(4, 47)),
new ErrorCorrectionBlocks(952, new ErrorCorrectionBlock(28, 22), new ErrorCorrectionBlock(6, 23)),
new ErrorCorrectionBlocks(1110, new ErrorCorrectionBlock(33, 16), new ErrorCorrectionBlock(4, 17))),
new QRCodeVersion(
27,
1828,
new ErrorCorrectionBlocks(360, new ErrorCorrectionBlock(8, 122), new ErrorCorrectionBlock(4, 123)),
new ErrorCorrectionBlocks(700, new ErrorCorrectionBlock(22, 45), new ErrorCorrectionBlock(3, 46)),
new ErrorCorrectionBlocks(1020, new ErrorCorrectionBlock(8, 23), new ErrorCorrectionBlock(26, 24)),
new ErrorCorrectionBlocks(1200, new ErrorCorrectionBlock(12, 15), new ErrorCorrectionBlock(28, 16))),
new QRCodeVersion(
28,
1921,
new ErrorCorrectionBlocks(390, new ErrorCorrectionBlock(3, 117), new ErrorCorrectionBlock(10, 118)),
new ErrorCorrectionBlocks(728, new ErrorCorrectionBlock(3, 45), new ErrorCorrectionBlock(23, 46)),
new ErrorCorrectionBlocks(1050, new ErrorCorrectionBlock(4, 24), new ErrorCorrectionBlock(31, 25)),
new ErrorCorrectionBlocks(1260, new ErrorCorrectionBlock(11, 15), new ErrorCorrectionBlock(31, 16))),
new QRCodeVersion(
29,
2051,
new ErrorCorrectionBlocks(420, new ErrorCorrectionBlock(7, 116), new ErrorCorrectionBlock(7, 117)),
new ErrorCorrectionBlocks(784, new ErrorCorrectionBlock(21, 45), new ErrorCorrectionBlock(7, 46)),
new ErrorCorrectionBlocks(1140, new ErrorCorrectionBlock(1, 23), new ErrorCorrectionBlock(37, 24)),
new ErrorCorrectionBlocks(1350, new ErrorCorrectionBlock(19, 15), new ErrorCorrectionBlock(26, 16))),
new QRCodeVersion(
30,
2185,
new ErrorCorrectionBlocks(450, new ErrorCorrectionBlock(5, 115), new ErrorCorrectionBlock(10, 116)),
new ErrorCorrectionBlocks(812, new ErrorCorrectionBlock(19, 47), new ErrorCorrectionBlock(10, 48)),
new ErrorCorrectionBlocks(1200, new ErrorCorrectionBlock(15, 24), new ErrorCorrectionBlock(25, 25)),
new ErrorCorrectionBlocks(1440, new ErrorCorrectionBlock(23, 15), new ErrorCorrectionBlock(25, 16))),
new QRCodeVersion(
31,
2323,
new ErrorCorrectionBlocks(480, new ErrorCorrectionBlock(13, 115), new ErrorCorrectionBlock(3, 116)),
new ErrorCorrectionBlocks(868, new ErrorCorrectionBlock(2, 46), new ErrorCorrectionBlock(29, 47)),
new ErrorCorrectionBlocks(1290, new ErrorCorrectionBlock(42, 24), new ErrorCorrectionBlock(1, 25)),
new ErrorCorrectionBlocks(1530, new ErrorCorrectionBlock(23, 15), new ErrorCorrectionBlock(28, 16))),
new QRCodeVersion(
32,
2465,
new ErrorCorrectionBlocks(510, new ErrorCorrectionBlock(17, 115)),
new ErrorCorrectionBlocks(924, new ErrorCorrectionBlock(10, 46), new ErrorCorrectionBlock(23, 47)),
new ErrorCorrectionBlocks(1350, new ErrorCorrectionBlock(10, 24), new ErrorCorrectionBlock(35, 25)),
new ErrorCorrectionBlocks(1620, new ErrorCorrectionBlock(19, 15), new ErrorCorrectionBlock(35, 16))),
new QRCodeVersion(
33,
2611,
new ErrorCorrectionBlocks(540, new ErrorCorrectionBlock(17, 115), new ErrorCorrectionBlock(1, 116)),
new ErrorCorrectionBlocks(980, new ErrorCorrectionBlock(14, 46), new ErrorCorrectionBlock(21, 47)),
new ErrorCorrectionBlocks(1440, new ErrorCorrectionBlock(29, 24), new ErrorCorrectionBlock(19, 25)),
new ErrorCorrectionBlocks(1710, new ErrorCorrectionBlock(11, 15), new ErrorCorrectionBlock(46, 16))),
new QRCodeVersion(
34,
2761,
new ErrorCorrectionBlocks(570, new ErrorCorrectionBlock(13, 115), new ErrorCorrectionBlock(6, 116)),
new ErrorCorrectionBlocks(1036, new ErrorCorrectionBlock(14, 46), new ErrorCorrectionBlock(23, 47)),
new ErrorCorrectionBlocks(1530, new ErrorCorrectionBlock(44, 24), new ErrorCorrectionBlock(7, 25)),
new ErrorCorrectionBlocks(1800, new ErrorCorrectionBlock(59, 16), new ErrorCorrectionBlock(1, 17))),
new QRCodeVersion(
35,
2876,
new ErrorCorrectionBlocks(570, new ErrorCorrectionBlock(12, 121), new ErrorCorrectionBlock(7, 122)),
new ErrorCorrectionBlocks(1064, new ErrorCorrectionBlock(12, 47), new ErrorCorrectionBlock(26, 48)),
new ErrorCorrectionBlocks(1590, new ErrorCorrectionBlock(39, 24), new ErrorCorrectionBlock(14, 25)),
new ErrorCorrectionBlocks(1890, new ErrorCorrectionBlock(22, 15), new ErrorCorrectionBlock(41, 16))),
new QRCodeVersion(
36,
3034,
new ErrorCorrectionBlocks(600, new ErrorCorrectionBlock(6, 121), new ErrorCorrectionBlock(14, 122)),
new ErrorCorrectionBlocks(1120, new ErrorCorrectionBlock(6, 47), new ErrorCorrectionBlock(34, 48)),
new ErrorCorrectionBlocks(1680, new ErrorCorrectionBlock(46, 24), new ErrorCorrectionBlock(10, 25)),
new ErrorCorrectionBlocks(1980, new ErrorCorrectionBlock(2, 15), new ErrorCorrectionBlock(64, 16))),
new QRCodeVersion(
37,
3196,
new ErrorCorrectionBlocks(630, new ErrorCorrectionBlock(17, 122), new ErrorCorrectionBlock(4, 123)),
new ErrorCorrectionBlocks(1204, new ErrorCorrectionBlock(29, 46), new ErrorCorrectionBlock(14, 47)),
new ErrorCorrectionBlocks(1770, new ErrorCorrectionBlock(49, 24), new ErrorCorrectionBlock(10, 25)),
new ErrorCorrectionBlocks(2100, new ErrorCorrectionBlock(24, 15), new ErrorCorrectionBlock(46, 16))),
new QRCodeVersion(
38,
3362,
new ErrorCorrectionBlocks(660, new ErrorCorrectionBlock(4, 122), new ErrorCorrectionBlock(18, 123)),
new ErrorCorrectionBlocks(1260, new ErrorCorrectionBlock(13, 46), new ErrorCorrectionBlock(32, 47)),
new ErrorCorrectionBlocks(1860, new ErrorCorrectionBlock(48, 24), new ErrorCorrectionBlock(14, 25)),
new ErrorCorrectionBlocks(2220, new ErrorCorrectionBlock(42, 15), new ErrorCorrectionBlock(32, 16))),
new QRCodeVersion(
39,
3532,
new ErrorCorrectionBlocks(720, new ErrorCorrectionBlock(20, 117), new ErrorCorrectionBlock(4, 118)),
new ErrorCorrectionBlocks(1316, new ErrorCorrectionBlock(40, 47), new ErrorCorrectionBlock(7, 48)),
new ErrorCorrectionBlocks(1950, new ErrorCorrectionBlock(43, 24), new ErrorCorrectionBlock(22, 25)),
new ErrorCorrectionBlocks(2310, new ErrorCorrectionBlock(10, 15), new ErrorCorrectionBlock(67, 16))),
new QRCodeVersion(
40,
3706,
new ErrorCorrectionBlocks(750, new ErrorCorrectionBlock(19, 118), new ErrorCorrectionBlock(6, 119)),
new ErrorCorrectionBlocks(1372, new ErrorCorrectionBlock(18, 47), new ErrorCorrectionBlock(31, 48)),
new ErrorCorrectionBlocks(2040, new ErrorCorrectionBlock(34, 24), new ErrorCorrectionBlock(34, 25)),
new ErrorCorrectionBlocks(2430, new ErrorCorrectionBlock(20, 15), new ErrorCorrectionBlock(61, 16))),
};
}
}
private static QRCodeVersion[] Initialize()
{
return new QRCodeVersion[]
{
new QRCodeVersion(
1,
26,
new ErrorCorrectionBlocks(7, new ErrorCorrectionBlock(1, 19)),
new ErrorCorrectionBlocks(10, new ErrorCorrectionBlock(1, 16)),
new ErrorCorrectionBlocks(13, new ErrorCorrectionBlock(1, 13)),
new ErrorCorrectionBlocks(17, new ErrorCorrectionBlock(1, 9))),
new QRCodeVersion(
2,
44,
new ErrorCorrectionBlocks(10, new ErrorCorrectionBlock(1, 34)),
new ErrorCorrectionBlocks(16, new ErrorCorrectionBlock(1, 28)),
new ErrorCorrectionBlocks(22, new ErrorCorrectionBlock(1, 22)),
new ErrorCorrectionBlocks(28, new ErrorCorrectionBlock(1, 16))),
new QRCodeVersion(
3,
70,
new ErrorCorrectionBlocks(15, new ErrorCorrectionBlock(1, 55)),
new ErrorCorrectionBlocks(26, new ErrorCorrectionBlock(1, 44)),
new ErrorCorrectionBlocks(36, new ErrorCorrectionBlock(2, 17)),
new ErrorCorrectionBlocks(44, new ErrorCorrectionBlock(2, 13))),
new QRCodeVersion(
4,
100,
new ErrorCorrectionBlocks(20, new ErrorCorrectionBlock(1, 80)),
new ErrorCorrectionBlocks(36, new ErrorCorrectionBlock(2, 32)),
new ErrorCorrectionBlocks(52, new ErrorCorrectionBlock(2, 24)),
new ErrorCorrectionBlocks(64, new ErrorCorrectionBlock(4, 9))),
new QRCodeVersion(
5,
134,
new ErrorCorrectionBlocks(26, new ErrorCorrectionBlock(1, 108)),
new ErrorCorrectionBlocks(48, new ErrorCorrectionBlock(2, 43)),
new ErrorCorrectionBlocks(72, new ErrorCorrectionBlock(2, 15), new ErrorCorrectionBlock(2, 16)),
new ErrorCorrectionBlocks(88, new ErrorCorrectionBlock(2, 11), new ErrorCorrectionBlock(2, 12))),
new QRCodeVersion(
6,
172,
new ErrorCorrectionBlocks(36, new ErrorCorrectionBlock(2, 68)),
new ErrorCorrectionBlocks(64, new ErrorCorrectionBlock(4, 27)),
new ErrorCorrectionBlocks(96, new ErrorCorrectionBlock(4, 19)),
new ErrorCorrectionBlocks(112, new ErrorCorrectionBlock(4, 15))),
new QRCodeVersion(
7,
196,
new ErrorCorrectionBlocks(40, new ErrorCorrectionBlock(2, 78)),
new ErrorCorrectionBlocks(72, new ErrorCorrectionBlock(4, 31)),
new ErrorCorrectionBlocks(108, new ErrorCorrectionBlock(2, 14), new ErrorCorrectionBlock(4, 15)),
new ErrorCorrectionBlocks(130, new ErrorCorrectionBlock(4, 13), new ErrorCorrectionBlock(1, 14))),
new QRCodeVersion(
8,
242,
new ErrorCorrectionBlocks(48, new ErrorCorrectionBlock(2, 97)),
new ErrorCorrectionBlocks(88, new ErrorCorrectionBlock(2, 38), new ErrorCorrectionBlock(2, 39)),
new ErrorCorrectionBlocks(132, new ErrorCorrectionBlock(4, 18), new ErrorCorrectionBlock(2, 19)),
new ErrorCorrectionBlocks(156, new ErrorCorrectionBlock(4, 14), new ErrorCorrectionBlock(2, 15))),
new QRCodeVersion(
9,
292,
new ErrorCorrectionBlocks(60, new ErrorCorrectionBlock(2, 116)),
new ErrorCorrectionBlocks(110, new ErrorCorrectionBlock(3, 36), new ErrorCorrectionBlock(2, 37)),
new ErrorCorrectionBlocks(160, new ErrorCorrectionBlock(4, 16), new ErrorCorrectionBlock(4, 17)),
new ErrorCorrectionBlocks(192, new ErrorCorrectionBlock(4, 12), new ErrorCorrectionBlock(4, 13))),
new QRCodeVersion(
10,
346,
new ErrorCorrectionBlocks(72, new ErrorCorrectionBlock(2, 68), new ErrorCorrectionBlock(2, 69)),
new ErrorCorrectionBlocks(130, new ErrorCorrectionBlock(4, 43), new ErrorCorrectionBlock(1, 44)),
new ErrorCorrectionBlocks(192, new ErrorCorrectionBlock(6, 19), new ErrorCorrectionBlock(2, 20)),
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(6, 15), new ErrorCorrectionBlock(2, 16))),
new QRCodeVersion(
11,
404,
new ErrorCorrectionBlocks(80, new ErrorCorrectionBlock(4, 81)),
new ErrorCorrectionBlocks(150, new ErrorCorrectionBlock(1, 50), new ErrorCorrectionBlock(4, 51)),
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(4, 22), new ErrorCorrectionBlock(4, 23)),
new ErrorCorrectionBlocks(264, new ErrorCorrectionBlock(3, 12), new ErrorCorrectionBlock(8, 13))),
new QRCodeVersion(
12,
466,
new ErrorCorrectionBlocks(96, new ErrorCorrectionBlock(2, 92), new ErrorCorrectionBlock(2, 93)),
new ErrorCorrectionBlocks(176, new ErrorCorrectionBlock(6, 36), new ErrorCorrectionBlock(2, 37)),
new ErrorCorrectionBlocks(260, new ErrorCorrectionBlock(4, 20), new ErrorCorrectionBlock(6, 21)),
new ErrorCorrectionBlocks(308, new ErrorCorrectionBlock(7, 14), new ErrorCorrectionBlock(4, 15))),
new QRCodeVersion(
13,
532,
new ErrorCorrectionBlocks(104, new ErrorCorrectionBlock(4, 107)),
new ErrorCorrectionBlocks(198, new ErrorCorrectionBlock(8, 37), new ErrorCorrectionBlock(1, 38)),
new ErrorCorrectionBlocks(288, new ErrorCorrectionBlock(8, 20), new ErrorCorrectionBlock(4, 21)),
new ErrorCorrectionBlocks(352, new ErrorCorrectionBlock(12, 11), new ErrorCorrectionBlock(4, 12))),
new QRCodeVersion(
14,
581,
new ErrorCorrectionBlocks(120, new ErrorCorrectionBlock(3, 115), new ErrorCorrectionBlock(1, 116)),
new ErrorCorrectionBlocks(216, new ErrorCorrectionBlock(4, 40), new ErrorCorrectionBlock(5, 41)),
new ErrorCorrectionBlocks(320, new ErrorCorrectionBlock(11, 16), new ErrorCorrectionBlock(5, 17)),
new ErrorCorrectionBlocks(384, new ErrorCorrectionBlock(11, 12), new ErrorCorrectionBlock(5, 13))),
new QRCodeVersion(
15,
655,
new ErrorCorrectionBlocks(132, new ErrorCorrectionBlock(5, 87), new ErrorCorrectionBlock(1, 88)),
new ErrorCorrectionBlocks(240, new ErrorCorrectionBlock(5, 41), new ErrorCorrectionBlock(5, 42)),
new ErrorCorrectionBlocks(360, new ErrorCorrectionBlock(5, 24), new ErrorCorrectionBlock(7, 25)),
new ErrorCorrectionBlocks(432, new ErrorCorrectionBlock(11, 12), new ErrorCorrectionBlock(7, 13))),
new QRCodeVersion(
16,
733,
new ErrorCorrectionBlocks(144, new ErrorCorrectionBlock(5, 98), new ErrorCorrectionBlock(1, 99)),
new ErrorCorrectionBlocks(280, new ErrorCorrectionBlock(7, 45), new ErrorCorrectionBlock(3, 46)),
new ErrorCorrectionBlocks(408, new ErrorCorrectionBlock(15, 19), new ErrorCorrectionBlock(2, 20)),
new ErrorCorrectionBlocks(480, new ErrorCorrectionBlock(3, 15), new ErrorCorrectionBlock(13, 16))),
new QRCodeVersion(
17,
815,
new ErrorCorrectionBlocks(168, new ErrorCorrectionBlock(1, 107), new ErrorCorrectionBlock(5, 108)),
new ErrorCorrectionBlocks(308, new ErrorCorrectionBlock(10, 46), new ErrorCorrectionBlock(1, 47)),
new ErrorCorrectionBlocks(448, new ErrorCorrectionBlock(1, 22), new ErrorCorrectionBlock(15, 23)),
new ErrorCorrectionBlocks(532, new ErrorCorrectionBlock(2, 14), new ErrorCorrectionBlock(17, 15))),
new QRCodeVersion(
18,
901,
new ErrorCorrectionBlocks(180, new ErrorCorrectionBlock(5, 120), new ErrorCorrectionBlock(1, 121)),
new ErrorCorrectionBlocks(338, new ErrorCorrectionBlock(9, 43), new ErrorCorrectionBlock(4, 44)),
new ErrorCorrectionBlocks(504, new ErrorCorrectionBlock(17, 22), new ErrorCorrectionBlock(1, 23)),
new ErrorCorrectionBlocks(588, new ErrorCorrectionBlock(2, 14), new ErrorCorrectionBlock(19, 15))),
new QRCodeVersion(
19,
991,
new ErrorCorrectionBlocks(196, new ErrorCorrectionBlock(3, 113), new ErrorCorrectionBlock(4, 114)),
new ErrorCorrectionBlocks(364, new ErrorCorrectionBlock(3, 44), new ErrorCorrectionBlock(11, 45)),
new ErrorCorrectionBlocks(546, new ErrorCorrectionBlock(17, 21), new ErrorCorrectionBlock(4, 22)),
new ErrorCorrectionBlocks(650, new ErrorCorrectionBlock(9, 13), new ErrorCorrectionBlock(16, 14))),
new QRCodeVersion(
20,
1085,
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(3, 107), new ErrorCorrectionBlock(5, 108)),
new ErrorCorrectionBlocks(416, new ErrorCorrectionBlock(3, 41), new ErrorCorrectionBlock(13, 42)),
new ErrorCorrectionBlocks(600, new ErrorCorrectionBlock(15, 24), new ErrorCorrectionBlock(5, 25)),
new ErrorCorrectionBlocks(700, new ErrorCorrectionBlock(15, 15), new ErrorCorrectionBlock(10, 16))),
new QRCodeVersion(
21,
1156,
new ErrorCorrectionBlocks(224, new ErrorCorrectionBlock(4, 116), new ErrorCorrectionBlock(4, 117)),
new ErrorCorrectionBlocks(442, new ErrorCorrectionBlock(17, 42)),
new ErrorCorrectionBlocks(644, new ErrorCorrectionBlock(17, 22), new ErrorCorrectionBlock(6, 23)),
new ErrorCorrectionBlocks(750, new ErrorCorrectionBlock(19, 16), new ErrorCorrectionBlock(6, 17))),
new QRCodeVersion(
22,
1258,
new ErrorCorrectionBlocks(252, new ErrorCorrectionBlock(2, 111), new ErrorCorrectionBlock(7, 112)),
new ErrorCorrectionBlocks(476, new ErrorCorrectionBlock(17, 46)),
new ErrorCorrectionBlocks(690, new ErrorCorrectionBlock(7, 24), new ErrorCorrectionBlock(16, 25)),
new ErrorCorrectionBlocks(816, new ErrorCorrectionBlock(34, 13))),
new QRCodeVersion(
23,
1364,
new ErrorCorrectionBlocks(270, new ErrorCorrectionBlock(4, 121), new ErrorCorrectionBlock(5, 122)),
new ErrorCorrectionBlocks(504, new ErrorCorrectionBlock(4, 47), new ErrorCorrectionBlock(14, 48)),
new ErrorCorrectionBlocks(750, new ErrorCorrectionBlock(11, 24), new ErrorCorrectionBlock(14, 25)),
new ErrorCorrectionBlocks(900, new ErrorCorrectionBlock(16, 15), new ErrorCorrectionBlock(14, 16))),
new QRCodeVersion(
24,
1474,
new ErrorCorrectionBlocks(300, new ErrorCorrectionBlock(6, 117), new ErrorCorrectionBlock(4, 118)),
new ErrorCorrectionBlocks(560, new ErrorCorrectionBlock(6, 45), new ErrorCorrectionBlock(14, 46)),
new ErrorCorrectionBlocks(810, new ErrorCorrectionBlock(11, 24), new ErrorCorrectionBlock(16, 25)),
new ErrorCorrectionBlocks(960, new ErrorCorrectionBlock(30, 16), new ErrorCorrectionBlock(2, 17))),
new QRCodeVersion(
25,
1588,
new ErrorCorrectionBlocks(312, new ErrorCorrectionBlock(8, 106), new ErrorCorrectionBlock(4, 107)),
new ErrorCorrectionBlocks(588, new ErrorCorrectionBlock(8, 47), new ErrorCorrectionBlock(13, 48)),
new ErrorCorrectionBlocks(870, new ErrorCorrectionBlock(7, 24), new ErrorCorrectionBlock(22, 25)),
new ErrorCorrectionBlocks(1050, new ErrorCorrectionBlock(22, 15), new ErrorCorrectionBlock(13, 16))),
new QRCodeVersion(
26,
1706,
new ErrorCorrectionBlocks(336, new ErrorCorrectionBlock(10, 114), new ErrorCorrectionBlock(2, 115)),
new ErrorCorrectionBlocks(644, new ErrorCorrectionBlock(19, 46), new ErrorCorrectionBlock(4, 47)),
new ErrorCorrectionBlocks(952, new ErrorCorrectionBlock(28, 22), new ErrorCorrectionBlock(6, 23)),
new ErrorCorrectionBlocks(1110, new ErrorCorrectionBlock(33, 16), new ErrorCorrectionBlock(4, 17))),
new QRCodeVersion(
27,
1828,
new ErrorCorrectionBlocks(360, new ErrorCorrectionBlock(8, 122), new ErrorCorrectionBlock(4, 123)),
new ErrorCorrectionBlocks(700, new ErrorCorrectionBlock(22, 45), new ErrorCorrectionBlock(3, 46)),
new ErrorCorrectionBlocks(1020, new ErrorCorrectionBlock(8, 23), new ErrorCorrectionBlock(26, 24)),
new ErrorCorrectionBlocks(1200, new ErrorCorrectionBlock(12, 15), new ErrorCorrectionBlock(28, 16))),
new QRCodeVersion(
28,
1921,
new ErrorCorrectionBlocks(390, new ErrorCorrectionBlock(3, 117), new ErrorCorrectionBlock(10, 118)),
new ErrorCorrectionBlocks(728, new ErrorCorrectionBlock(3, 45), new ErrorCorrectionBlock(23, 46)),
new ErrorCorrectionBlocks(1050, new ErrorCorrectionBlock(4, 24), new ErrorCorrectionBlock(31, 25)),
new ErrorCorrectionBlocks(1260, new ErrorCorrectionBlock(11, 15), new ErrorCorrectionBlock(31, 16))),
new QRCodeVersion(
29,
2051,
new ErrorCorrectionBlocks(420, new ErrorCorrectionBlock(7, 116), new ErrorCorrectionBlock(7, 117)),
new ErrorCorrectionBlocks(784, new ErrorCorrectionBlock(21, 45), new ErrorCorrectionBlock(7, 46)),
new ErrorCorrectionBlocks(1140, new ErrorCorrectionBlock(1, 23), new ErrorCorrectionBlock(37, 24)),
new ErrorCorrectionBlocks(1350, new ErrorCorrectionBlock(19, 15), new ErrorCorrectionBlock(26, 16))),
new QRCodeVersion(
30,
2185,
new ErrorCorrectionBlocks(450, new ErrorCorrectionBlock(5, 115), new ErrorCorrectionBlock(10, 116)),
new ErrorCorrectionBlocks(812, new ErrorCorrectionBlock(19, 47), new ErrorCorrectionBlock(10, 48)),
new ErrorCorrectionBlocks(1200, new ErrorCorrectionBlock(15, 24), new ErrorCorrectionBlock(25, 25)),
new ErrorCorrectionBlocks(1440, new ErrorCorrectionBlock(23, 15), new ErrorCorrectionBlock(25, 16))),
new QRCodeVersion(
31,
2323,
new ErrorCorrectionBlocks(480, new ErrorCorrectionBlock(13, 115), new ErrorCorrectionBlock(3, 116)),
new ErrorCorrectionBlocks(868, new ErrorCorrectionBlock(2, 46), new ErrorCorrectionBlock(29, 47)),
new ErrorCorrectionBlocks(1290, new ErrorCorrectionBlock(42, 24), new ErrorCorrectionBlock(1, 25)),
new ErrorCorrectionBlocks(1530, new ErrorCorrectionBlock(23, 15), new ErrorCorrectionBlock(28, 16))),
new QRCodeVersion(
32,
2465,
new ErrorCorrectionBlocks(510, new ErrorCorrectionBlock(17, 115)),
new ErrorCorrectionBlocks(924, new ErrorCorrectionBlock(10, 46), new ErrorCorrectionBlock(23, 47)),
new ErrorCorrectionBlocks(1350, new ErrorCorrectionBlock(10, 24), new ErrorCorrectionBlock(35, 25)),
new ErrorCorrectionBlocks(1620, new ErrorCorrectionBlock(19, 15), new ErrorCorrectionBlock(35, 16))),
new QRCodeVersion(
33,
2611,
new ErrorCorrectionBlocks(540, new ErrorCorrectionBlock(17, 115), new ErrorCorrectionBlock(1, 116)),
new ErrorCorrectionBlocks(980, new ErrorCorrectionBlock(14, 46), new ErrorCorrectionBlock(21, 47)),
new ErrorCorrectionBlocks(1440, new ErrorCorrectionBlock(29, 24), new ErrorCorrectionBlock(19, 25)),
new ErrorCorrectionBlocks(1710, new ErrorCorrectionBlock(11, 15), new ErrorCorrectionBlock(46, 16))),
new QRCodeVersion(
34,
2761,
new ErrorCorrectionBlocks(570, new ErrorCorrectionBlock(13, 115), new ErrorCorrectionBlock(6, 116)),
new ErrorCorrectionBlocks(1036, new ErrorCorrectionBlock(14, 46), new ErrorCorrectionBlock(23, 47)),
new ErrorCorrectionBlocks(1530, new ErrorCorrectionBlock(44, 24), new ErrorCorrectionBlock(7, 25)),
new ErrorCorrectionBlocks(1800, new ErrorCorrectionBlock(59, 16), new ErrorCorrectionBlock(1, 17))),
new QRCodeVersion(
35,
2876,
new ErrorCorrectionBlocks(570, new ErrorCorrectionBlock(12, 121), new ErrorCorrectionBlock(7, 122)),
new ErrorCorrectionBlocks(1064, new ErrorCorrectionBlock(12, 47), new ErrorCorrectionBlock(26, 48)),
new ErrorCorrectionBlocks(1590, new ErrorCorrectionBlock(39, 24), new ErrorCorrectionBlock(14, 25)),
new ErrorCorrectionBlocks(1890, new ErrorCorrectionBlock(22, 15), new ErrorCorrectionBlock(41, 16))),
new QRCodeVersion(
36,
3034,
new ErrorCorrectionBlocks(600, new ErrorCorrectionBlock(6, 121), new ErrorCorrectionBlock(14, 122)),
new ErrorCorrectionBlocks(1120, new ErrorCorrectionBlock(6, 47), new ErrorCorrectionBlock(34, 48)),
new ErrorCorrectionBlocks(1680, new ErrorCorrectionBlock(46, 24), new ErrorCorrectionBlock(10, 25)),
new ErrorCorrectionBlocks(1980, new ErrorCorrectionBlock(2, 15), new ErrorCorrectionBlock(64, 16))),
new QRCodeVersion(
37,
3196,
new ErrorCorrectionBlocks(630, new ErrorCorrectionBlock(17, 122), new ErrorCorrectionBlock(4, 123)),
new ErrorCorrectionBlocks(1204, new ErrorCorrectionBlock(29, 46), new ErrorCorrectionBlock(14, 47)),
new ErrorCorrectionBlocks(1770, new ErrorCorrectionBlock(49, 24), new ErrorCorrectionBlock(10, 25)),
new ErrorCorrectionBlocks(2100, new ErrorCorrectionBlock(24, 15), new ErrorCorrectionBlock(46, 16))),
new QRCodeVersion(
38,
3362,
new ErrorCorrectionBlocks(660, new ErrorCorrectionBlock(4, 122), new ErrorCorrectionBlock(18, 123)),
new ErrorCorrectionBlocks(1260, new ErrorCorrectionBlock(13, 46), new ErrorCorrectionBlock(32, 47)),
new ErrorCorrectionBlocks(1860, new ErrorCorrectionBlock(48, 24), new ErrorCorrectionBlock(14, 25)),
new ErrorCorrectionBlocks(2220, new ErrorCorrectionBlock(42, 15), new ErrorCorrectionBlock(32, 16))),
new QRCodeVersion(
39,
3532,
new ErrorCorrectionBlocks(720, new ErrorCorrectionBlock(20, 117), new ErrorCorrectionBlock(4, 118)),
new ErrorCorrectionBlocks(1316, new ErrorCorrectionBlock(40, 47), new ErrorCorrectionBlock(7, 48)),
new ErrorCorrectionBlocks(1950, new ErrorCorrectionBlock(43, 24), new ErrorCorrectionBlock(22, 25)),
new ErrorCorrectionBlocks(2310, new ErrorCorrectionBlock(10, 15), new ErrorCorrectionBlock(67, 16))),
new QRCodeVersion(
40,
3706,
new ErrorCorrectionBlocks(750, new ErrorCorrectionBlock(19, 118), new ErrorCorrectionBlock(6, 119)),
new ErrorCorrectionBlocks(1372, new ErrorCorrectionBlock(18, 47), new ErrorCorrectionBlock(31, 48)),
new ErrorCorrectionBlocks(2040, new ErrorCorrectionBlock(34, 24), new ErrorCorrectionBlock(34, 25)),
new ErrorCorrectionBlocks(2430, new ErrorCorrectionBlock(20, 15), new ErrorCorrectionBlock(61, 16))),
};
}
}