Skip to content

Commit 5a97eb2

Browse files
committed
update
1 parent 7546d16 commit 5a97eb2

File tree

5 files changed

+148
-118
lines changed

5 files changed

+148
-118
lines changed

QRCoder/QRCodeGenerator.cs

+3-48
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ namespace QRCoder;
1616
/// </summary>
1717
public partial class QRCodeGenerator : IDisposable
1818
{
19-
/// <summary>
20-
/// A lookup table mapping QR code versions to their corresponding alignment patterns.
21-
/// </summary>
22-
private static readonly Dictionary<int, AlignmentPattern> _alignmentPatternTable = Tables.CreateAlignmentPatternTable();
23-
2419
/// <summary>
2520
/// A table containing the error correction capacities and data codeword information for different combinations of QR code versions and error correction levels.
2621
/// </summary>
@@ -32,12 +27,6 @@ public partial class QRCodeGenerator : IDisposable
3227
/// </summary>
3328
private static readonly List<VersionInfo> _capacityTable = Tables.CreateCapacityTable();
3429

35-
/// <summary>
36-
/// A dictionary mapping alphanumeric characters to their respective positions used in QR code encoding.
37-
/// This includes digits 0-9, uppercase letters A-Z, and some special characters.
38-
/// </summary>
39-
private static readonly Dictionary<char, int> _alphanumEncDict = Tables.CreateAlphanumEncDict();
40-
4130
/// <summary>
4231
/// Initializes the QR code generator
4332
/// </summary>
@@ -348,7 +337,7 @@ QRCodeData PlaceModules()
348337
{
349338
ModulePlacer.PlaceFinderPatterns(qr, blockedModules);
350339
ModulePlacer.ReserveSeperatorAreas(size, blockedModules);
351-
ModulePlacer.PlaceAlignmentPatterns(qr, _alignmentPatternTable[version].PatternPositions, blockedModules);
340+
ModulePlacer.PlaceAlignmentPatterns(qr, AlignmentPatterns.FromVersion(version).PatternPositions, blockedModules);
352341
ModulePlacer.PlaceTimingPatterns(qr, blockedModules);
353342
ModulePlacer.PlaceDarkModule(qr, version, blockedModules);
354343
ModulePlacer.ReserveVersionAreas(size, version, blockedModules);
@@ -623,7 +612,7 @@ private static EncodingMode GetEncodingFromPlaintext(string plainText, bool forc
623612
if (IsInRange(c, '0', '9'))
624613
continue; // numeric - char.IsDigit() for Latin1
625614
result = EncodingMode.Alphanumeric; // not numeric, assume alphanumeric
626-
if (IsInRange(c, 'A', 'Z') || Tables.AlphanumEncTableContains(c))
615+
if (AlphanumericEncoder.CanEncode(c))
627616
continue; // alphanumeric
628617
return EncodingMode.Byte; // not numeric or alphanumeric, assume byte
629618
}
@@ -804,7 +793,7 @@ private static BitArray PlainTextToBinary(string plainText, EncodingMode encMode
804793
{
805794
return encMode switch
806795
{
807-
EncodingMode.Alphanumeric => PlainTextToBinaryAlphanumeric(plainText),
796+
EncodingMode.Alphanumeric => AlphanumericEncoder.GetBitArray(plainText),
808797
EncodingMode.Numeric => PlainTextToBinaryNumeric(plainText),
809798
EncodingMode.Byte => PlainTextToBinaryByte(plainText, eciMode, utf8BOM, forceUtf8),
810799
_ => _emptyBitArray,
@@ -862,40 +851,6 @@ private static BitArray PlainTextToBinaryNumeric(string plainText)
862851
return bitArray;
863852
}
864853

865-
/// <summary>
866-
/// Converts alphanumeric plain text into a binary format optimized for QR codes.
867-
/// Alphanumeric encoding packs characters into 11-bit groups for each pair of characters,
868-
/// and 6 bits for a single remaining character if the total count is odd.
869-
/// </summary>
870-
/// <param name="plainText">The alphanumeric text to be encoded, which should only contain characters valid in QR alphanumeric mode.</param>
871-
/// <returns>A BitArray representing the binary data of the encoded alphanumeric text.</returns>
872-
private static BitArray PlainTextToBinaryAlphanumeric(string plainText)
873-
{
874-
// Calculate the length of the BitArray needed based on the number of character pairs.
875-
var codeText = new BitArray((plainText.Length / 2) * 11 + (plainText.Length & 1) * 6);
876-
var codeIndex = 0;
877-
var index = 0;
878-
var count = plainText.Length;
879-
880-
// Process each pair of characters.
881-
while (count >= 2)
882-
{
883-
// Convert each pair of characters to a number by looking them up in the alphanumeric dictionary and calculating.
884-
var dec = _alphanumEncDict[plainText[index++]] * 45 + _alphanumEncDict[plainText[index++]];
885-
// Convert the number to binary and store it in the BitArray.
886-
codeIndex = DecToBin(dec, 11, codeText, codeIndex);
887-
count -= 2;
888-
}
889-
890-
// Handle the last character if the length is odd.
891-
if (count > 0)
892-
{
893-
DecToBin(_alphanumEncDict[plainText[index]], 6, codeText, codeIndex);
894-
}
895-
896-
return codeText;
897-
}
898-
899854
private static readonly Encoding _iso8859_1 =
900855
#if NET5_0_OR_GREATER
901856
Encoding.Latin1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System.Collections.Generic;
2+
3+
namespace QRCoder;
4+
5+
public partial class QRCodeGenerator
6+
{
7+
/// <summary>
8+
/// This class contains the alignment patterns used in QR codes.
9+
/// </summary>
10+
private static class AlignmentPatterns
11+
{
12+
/// <summary>
13+
/// A lookup table mapping QR code versions to their corresponding alignment patterns.
14+
/// </summary>
15+
private static readonly Dictionary<int, AlignmentPattern> _alignmentPatternTable = CreateAlignmentPatternTable();
16+
17+
/// <summary>
18+
/// Retrieves the alignment pattern for a specific QR code version.
19+
/// </summary>
20+
public static AlignmentPattern FromVersion(int version) => _alignmentPatternTable[version];
21+
22+
/// <summary>
23+
/// Creates a lookup table mapping QR code versions to their corresponding alignment patterns.
24+
/// Alignment patterns are used in QR codes to help scanners accurately read the code at high speeds and when partially obscured.
25+
/// This table provides the necessary patterns based on the QR code version which dictates the size and complexity of the QR code.
26+
/// </summary>
27+
/// <returns>A dictionary where keys are QR code version numbers and values are AlignmentPattern structures detailing the positions of alignment patterns for each version.</returns>
28+
private static Dictionary<int, AlignmentPattern> CreateAlignmentPatternTable()
29+
{
30+
var alignmentPatternBaseValues = new int[] { 0, 0, 0, 0, 0, 0, 0, 6, 18, 0, 0, 0, 0, 0, 6, 22, 0, 0, 0, 0, 0, 6, 26, 0, 0, 0, 0, 0, 6, 30, 0, 0, 0, 0, 0, 6, 34, 0, 0, 0, 0, 0, 6, 22, 38, 0, 0, 0, 0, 6, 24, 42, 0, 0, 0, 0, 6, 26, 46, 0, 0, 0, 0, 6, 28, 50, 0, 0, 0, 0, 6, 30, 54, 0, 0, 0, 0, 6, 32, 58, 0, 0, 0, 0, 6, 34, 62, 0, 0, 0, 0, 6, 26, 46, 66, 0, 0, 0, 6, 26, 48, 70, 0, 0, 0, 6, 26, 50, 74, 0, 0, 0, 6, 30, 54, 78, 0, 0, 0, 6, 30, 56, 82, 0, 0, 0, 6, 30, 58, 86, 0, 0, 0, 6, 34, 62, 90, 0, 0, 0, 6, 28, 50, 72, 94, 0, 0, 6, 26, 50, 74, 98, 0, 0, 6, 30, 54, 78, 102, 0, 0, 6, 28, 54, 80, 106, 0, 0, 6, 32, 58, 84, 110, 0, 0, 6, 30, 58, 86, 114, 0, 0, 6, 34, 62, 90, 118, 0, 0, 6, 26, 50, 74, 98, 122, 0, 6, 30, 54, 78, 102, 126, 0, 6, 26, 52, 78, 104, 130, 0, 6, 30, 56, 82, 108, 134, 0, 6, 34, 60, 86, 112, 138, 0, 6, 30, 58, 86, 114, 142, 0, 6, 34, 62, 90, 118, 146, 0, 6, 30, 54, 78, 102, 126, 150, 6, 24, 50, 76, 102, 128, 154, 6, 28, 54, 80, 106, 132, 158, 6, 32, 58, 84, 110, 136, 162, 6, 26, 54, 82, 110, 138, 166, 6, 30, 58, 86, 114, 142, 170 };
31+
var localAlignmentPatternTable = new Dictionary<int, AlignmentPattern>(40);
32+
33+
for (var i = 0; i < (7 * 40); i += 7)
34+
{
35+
var points = new List<Point>(50);
36+
for (var x = 0; x < 7; x++)
37+
{
38+
if (alignmentPatternBaseValues[i + x] != 0)
39+
{
40+
for (var y = 0; y < 7; y++)
41+
{
42+
if (alignmentPatternBaseValues[i + y] != 0)
43+
{
44+
var p = new Point(alignmentPatternBaseValues[i + x] - 2, alignmentPatternBaseValues[i + y] - 2);
45+
if (!points.Contains(p))
46+
points.Add(p);
47+
}
48+
}
49+
}
50+
}
51+
52+
var version = (i + 7) / 7;
53+
localAlignmentPatternTable.Add(version, new AlignmentPattern()
54+
{
55+
Version = version,
56+
PatternPositions = points
57+
});
58+
}
59+
return localAlignmentPatternTable;
60+
}
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
5+
namespace QRCoder;
6+
7+
public partial class QRCodeGenerator
8+
{
9+
/// <summary>
10+
/// Encodes alphanumeric characters (<c>0–9</c>, <c>A–Z</c> (uppercase), space, <c>$</c>, <c>%</c>, <c>*</c>, <c>+</c>, <c>-</c>, period, <c>/</c>, colon) into a binary format suitable for QR codes.
11+
/// </summary>
12+
private static class AlphanumericEncoder
13+
{
14+
private static readonly char[] _alphanumEncTable = { ' ', '$', '%', '*', '+', '-', '.', '/', ':' };
15+
16+
/// <summary>
17+
/// A dictionary mapping alphanumeric characters to their respective positions used in QR code encoding.
18+
/// This includes digits 0-9, uppercase letters A-Z, and some special characters.
19+
/// </summary>
20+
private static readonly Dictionary<char, int> _alphanumEncDict = CreateAlphanumEncDict(_alphanumEncTable);
21+
22+
/// <summary>
23+
/// Creates a dictionary mapping alphanumeric characters to their respective positions used in QR code encoding.
24+
/// This includes digits 0-9, uppercase letters A-Z, and some special characters.
25+
/// </summary>
26+
/// <returns>A dictionary mapping each supported alphanumeric character to its corresponding value.</returns>
27+
private static Dictionary<char, int> CreateAlphanumEncDict(char[] alphanumEncTable)
28+
{
29+
var localAlphanumEncDict = new Dictionary<char, int>(45);
30+
// Add 0-9
31+
for (char c = '0'; c <= '9'; c++)
32+
localAlphanumEncDict.Add(c, c - '0');
33+
// Add uppercase alphabetic characters.
34+
for (char c = 'A'; c <= 'Z'; c++)
35+
localAlphanumEncDict.Add(c, localAlphanumEncDict.Count);
36+
// Add special characters from a predefined table.
37+
for (int i = 0; i < _alphanumEncTable.Length; i++)
38+
localAlphanumEncDict.Add(alphanumEncTable[i], localAlphanumEncDict.Count);
39+
return localAlphanumEncDict;
40+
}
41+
42+
/// <summary>
43+
/// Checks if a character is present in the alphanumeric encoding table.
44+
/// </summary>
45+
public static bool CanEncode(char c) => IsInRange(c, 'A', 'Z') || Array.IndexOf(_alphanumEncTable, c) >= 0;
46+
47+
/// <summary>
48+
/// Converts alphanumeric plain text into a binary format optimized for QR codes.
49+
/// Alphanumeric encoding packs characters into 11-bit groups for each pair of characters,
50+
/// and 6 bits for a single remaining character if the total count is odd.
51+
/// </summary>
52+
/// <param name="plainText">The alphanumeric text to be encoded, which should only contain characters valid in QR alphanumeric mode.</param>
53+
/// <returns>A BitArray representing the binary data of the encoded alphanumeric text.</returns>
54+
public static BitArray GetBitArray(string plainText)
55+
{
56+
// Calculate the length of the BitArray needed based on the number of character pairs.
57+
var codeText = new BitArray((plainText.Length / 2) * 11 + (plainText.Length & 1) * 6);
58+
var codeIndex = 0;
59+
var index = 0;
60+
var count = plainText.Length;
61+
62+
// Process each pair of characters.
63+
while (count >= 2)
64+
{
65+
// Convert each pair of characters to a number by looking them up in the alphanumeric dictionary and calculating.
66+
var dec = _alphanumEncDict[plainText[index++]] * 45 + _alphanumEncDict[plainText[index++]];
67+
// Convert the number to binary and store it in the BitArray.
68+
codeIndex = DecToBin(dec, 11, codeText, codeIndex);
69+
count -= 2;
70+
}
71+
72+
// Handle the last character if the length is odd.
73+
if (count > 0)
74+
{
75+
DecToBin(_alphanumEncDict[plainText[index]], 6, codeText, codeIndex);
76+
}
77+
78+
return codeText;
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)