-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Split alphanumeric encoding from QRCodeGenerator, split encoding tables #590
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
1c87314
e10801d
5d16dca
f3d17c7
5941456
6b57a3f
7546d16
5a97eb2
ae3d1c2
ddb443c
e6fc48f
4bd7227
faac596
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace QRCoder; | ||
|
||
public partial class QRCodeGenerator | ||
{ | ||
/// <summary> | ||
/// This class contains the alignment patterns used in QR codes. | ||
/// </summary> | ||
private static class AlignmentPatterns | ||
{ | ||
/// <summary> | ||
/// A lookup table mapping QR code versions to their corresponding alignment patterns. | ||
/// </summary> | ||
private static readonly Dictionary<int, AlignmentPattern> _alignmentPatternTable = CreateAlignmentPatternTable(); | ||
|
||
/// <summary> | ||
/// Retrieves the alignment pattern for a specific QR code version. | ||
/// </summary> | ||
public static AlignmentPattern FromVersion(int version) => _alignmentPatternTable[version]; | ||
|
||
/// <summary> | ||
/// Creates a lookup table mapping QR code versions to their corresponding alignment patterns. | ||
/// Alignment patterns are used in QR codes to help scanners accurately read the code at high speeds and when partially obscured. | ||
/// This table provides the necessary patterns based on the QR code version which dictates the size and complexity of the QR code. | ||
/// </summary> | ||
/// <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> | ||
private static Dictionary<int, AlignmentPattern> CreateAlignmentPatternTable() | ||
{ | ||
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 }; | ||
var localAlignmentPatternTable = new Dictionary<int, AlignmentPattern>(40); | ||
|
||
for (var i = 0; i < (7 * 40); i += 7) | ||
{ | ||
var points = new List<Point>(50); | ||
for (var x = 0; x < 7; x++) | ||
{ | ||
if (alignmentPatternBaseValues[i + x] != 0) | ||
{ | ||
for (var y = 0; y < 7; y++) | ||
{ | ||
if (alignmentPatternBaseValues[i + y] != 0) | ||
{ | ||
var p = new Point(alignmentPatternBaseValues[i + x] - 2, alignmentPatternBaseValues[i + y] - 2); | ||
if (!points.Contains(p)) | ||
points.Add(p); | ||
} | ||
} | ||
} | ||
} | ||
|
||
var version = (i + 7) / 7; | ||
localAlignmentPatternTable.Add(version, new AlignmentPattern() | ||
{ | ||
Version = version, | ||
PatternPositions = points | ||
}); | ||
} | ||
return localAlignmentPatternTable; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
|
||
namespace QRCoder; | ||
|
||
public partial class QRCodeGenerator | ||
{ | ||
/// <summary> | ||
/// 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. | ||
/// </summary> | ||
private static class AlphanumericEncoder | ||
{ | ||
private static readonly char[] _alphanumEncTable = { ' ', '$', '%', '*', '+', '-', '.', '/', ':' }; | ||
|
||
/// <summary> | ||
/// A dictionary mapping alphanumeric characters to their respective positions used in QR code encoding. | ||
/// This includes digits 0-9, uppercase letters A-Z, and some special characters. | ||
/// </summary> | ||
private static readonly Dictionary<char, int> _alphanumEncDict = CreateAlphanumEncDict(_alphanumEncTable); | ||
|
||
/// <summary> | ||
/// Creates a dictionary mapping alphanumeric characters to their respective positions used in QR code encoding. | ||
/// This includes digits 0-9, uppercase letters A-Z, and some special characters. | ||
/// </summary> | ||
/// <returns>A dictionary mapping each supported alphanumeric character to its corresponding value.</returns> | ||
private static Dictionary<char, int> CreateAlphanumEncDict(char[] alphanumEncTable) | ||
{ | ||
var localAlphanumEncDict = new Dictionary<char, int>(45); | ||
// Add 0-9 | ||
for (char c = '0'; c <= '9'; c++) | ||
localAlphanumEncDict.Add(c, c - '0'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed from |
||
// Add uppercase alphabetic characters. | ||
for (char c = 'A'; c <= 'Z'; c++) | ||
localAlphanumEncDict.Add(c, localAlphanumEncDict.Count); | ||
// Add special characters from a predefined table. | ||
for (int i = 0; i < _alphanumEncTable.Length; i++) | ||
localAlphanumEncDict.Add(alphanumEncTable[i], localAlphanumEncDict.Count); | ||
return localAlphanumEncDict; | ||
} | ||
|
||
/// <summary> | ||
/// Checks if a character is present in the alphanumeric encoding table. | ||
/// </summary> | ||
public static bool CanEncode(char c) => IsInRange(c, 'A', 'Z') || Array.IndexOf(_alphanumEncTable, c) >= 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed from |
||
|
||
/// <summary> | ||
/// Converts alphanumeric plain text into a binary format optimized for QR codes. | ||
/// Alphanumeric encoding packs characters into 11-bit groups for each pair of characters, | ||
/// and 6 bits for a single remaining character if the total count is odd. | ||
/// </summary> | ||
/// <param name="plainText">The alphanumeric text to be encoded, which should only contain characters valid in QR alphanumeric mode.</param> | ||
/// <returns>A BitArray representing the binary data of the encoded alphanumeric text.</returns> | ||
public static BitArray GetBitArray(string plainText) | ||
{ | ||
// Calculate the length of the BitArray needed based on the number of character pairs. | ||
var codeText = new BitArray((plainText.Length / 2) * 11 + (plainText.Length & 1) * 6); | ||
var codeIndex = 0; | ||
var index = 0; | ||
var count = plainText.Length; | ||
|
||
// Process each pair of characters. | ||
while (count >= 2) | ||
{ | ||
// Convert each pair of characters to a number by looking them up in the alphanumeric dictionary and calculating. | ||
var dec = _alphanumEncDict[plainText[index++]] * 45 + _alphanumEncDict[plainText[index++]]; | ||
// Convert the number to binary and store it in the BitArray. | ||
codeIndex = DecToBin(dec, 11, codeText, codeIndex); | ||
count -= 2; | ||
} | ||
|
||
// Handle the last character if the length is odd. | ||
if (count > 0) | ||
{ | ||
DecToBin(_alphanumEncDict[plainText[index]], 6, codeText, codeIndex); | ||
} | ||
|
||
return codeText; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move from static field so that array is not retained in memory after creating the dictionary