Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions QRCoder.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
global.json = global.json
EndProjectSection
EndProject
Global
Expand Down
245 changes: 16 additions & 229 deletions QRCoder/QRCodeGenerator.cs

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions QRCoder/QRCodeGenerator/AlignmentPatterns.cs
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 };
Comment thread
codebude marked this conversation as resolved.
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;
}
}
}
81 changes: 81 additions & 0 deletions QRCoder/QRCodeGenerator/AlphanumericEncoder.cs
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');
Comment thread
codebude marked this conversation as resolved.
// 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;
Comment thread
codebude marked this conversation as resolved.

/// <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;
}
}
}
Loading