Skip to content

Bugfix/330 corrupt ascii qr code #339

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

Merged
merged 3 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
57 changes: 14 additions & 43 deletions QRCoder/ASCIIQRCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,7 @@ public AsciiQRCode() { }

public AsciiQRCode(QRCodeData data) : base(data) { }

/// <summary>
/// Returns a strings that contains the resulting QR code as ASCII chars.
/// </summary>
/// <param name="repeatPerModule">Number of repeated darkColorString/whiteSpaceString per module.</param>
/// <returns></returns>
public string GetGraphic(int repeatPerModule)
{
return string.Join("\n", GetLineByLineGraphic(repeatPerModule));
}



/// <summary>
/// Returns a strings that contains the resulting QR code as ASCII chars.
/// </summary>
Expand All @@ -33,22 +23,11 @@ public string GetGraphic(int repeatPerModule)
/// <param name="whiteSpaceString">String for use as white modules (whitespace). In case of string make sure darkColorString has the same length.</param>
/// <param name="endOfLine">End of line separator. (Default: \n)</param>
/// <returns></returns>
public string GetGraphic(int repeatPerModule, string darkColorString, string whiteSpaceString, string endOfLine = "\n")
public string GetGraphic(int repeatPerModule, string darkColorString = "██", string whiteSpaceString = " ", bool drawQuietZones = true, string endOfLine = "\n")
{
return string.Join(endOfLine, GetLineByLineGraphic(repeatPerModule, darkColorString, whiteSpaceString));
return string.Join(endOfLine, GetLineByLineGraphic(repeatPerModule, darkColorString, whiteSpaceString, drawQuietZones));
}


/// <summary>
/// Returns an array of strings that contains each line of the resulting QR code as ASCII chars.
/// </summary>
/// <param name="repeatPerModule">Number of repeated darkColorString/whiteSpaceString per module.</param>
/// <returns></returns>
public string[] GetLineByLineGraphic(int repeatPerModule)
{
return GetLineByLineGraphic(repeatPerModule, "██", " ");
}



/// <summary>
/// Returns an array of strings that contains each line of the resulting QR code as ASCII chars.
Expand All @@ -57,51 +36,43 @@ public string[] GetLineByLineGraphic(int repeatPerModule)
/// <param name="darkColorString">String for use as dark color modules. In case of string make sure whiteSpaceString has the same length.</param>
/// <param name="whiteSpaceString">String for use as white modules (whitespace). In case of string make sure darkColorString has the same length.</param>
/// <returns></returns>
public string[] GetLineByLineGraphic(int repeatPerModule, string darkColorString, string whiteSpaceString)
public string[] GetLineByLineGraphic(int repeatPerModule, string darkColorString = "██", string whiteSpaceString = " ", bool drawQuietZones = true)
{
var qrCode = new List<string>();
//We need to adjust the repeatPerModule based on number of characters in darkColorString
//(we assume whiteSpaceString has the same number of characters)
//to keep the QR code as square as possible.
var quietZonesModifier = (drawQuietZones ? 0 : 8);
var quietZonesOffset = (int)(quietZonesModifier * 0.5);
var adjustmentValueForNumberOfCharacters = darkColorString.Length / 2 != 1 ? darkColorString.Length / 2 : 0;
var verticalNumberOfRepeats = repeatPerModule + adjustmentValueForNumberOfCharacters;
var sideLength = QrCodeData.ModuleMatrix.Count * verticalNumberOfRepeats;
var sideLength = (QrCodeData.ModuleMatrix.Count - quietZonesModifier) * verticalNumberOfRepeats;
for (var y = 0; y < sideLength; y++)
{
bool emptyLine = true;
var lineBuilder = new StringBuilder();

for (var x = 0; x < QrCodeData.ModuleMatrix.Count; x++)
for (var x = 0; x < QrCodeData.ModuleMatrix.Count - quietZonesModifier; x++)
{
var module = QrCodeData.ModuleMatrix[x][(y + verticalNumberOfRepeats) / verticalNumberOfRepeats - 1];

var module = QrCodeData.ModuleMatrix[x + quietZonesOffset][((y + verticalNumberOfRepeats) / verticalNumberOfRepeats - 1)+quietZonesOffset];
for (var i = 0; i < repeatPerModule; i++)
{
lineBuilder.Append(module ? darkColorString : whiteSpaceString);
}
if (module)
{
emptyLine = false;
}
}
if (!emptyLine)
{
qrCode.Add(lineBuilder.ToString());
}

qrCode.Add(lineBuilder.ToString());
}
return qrCode.ToArray();
}
}


public static class AsciiQRCodeHelper
{
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorString, string whiteSpaceString, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, string endOfLine = "\n")
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorString, string whiteSpaceString, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, string endOfLine = "\n", bool drawQuietZones = true)
{
using (var qrGenerator = new QRCodeGenerator())
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
using (var qrCode = new AsciiQRCode(qrCodeData))
return qrCode.GetGraphic(pixelsPerModule, darkColorString, whiteSpaceString, endOfLine);
return qrCode.GetGraphic(pixelsPerModule, darkColorString, whiteSpaceString, drawQuietZones, endOfLine);
}
}
}
80 changes: 80 additions & 0 deletions QRCoderTests/AsciiQRCodeRendererTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using Xunit;
using QRCoder;
using Shouldly;
using QRCoderTests.XUnitExtenstions;


namespace QRCoderTests
{

public class AsciiQRCodeRendererTests
{

[Fact]
[Category("QRRenderer/AsciiQRCode")]
public void can_render_ascii_qrcode()
{
var targetCode = " \n \n \n \n ██████████████ ██ ██ ██████████████ \n ██ ██ ██ ████ ██ ██ \n ██ ██████ ██ ██ ██ ██ ██ ██████ ██ \n ██ ██████ ██ ██ ██ ██████ ██ \n ██ ██████ ██ ██ ██ ██████ ██ \n ██ ██ ████████ ██ ██ \n ██████████████ ██ ██ ██ ██████████████ \n ██ ████ \n ██████████ ████ ████████ ██ ████ \n ████ ██ ██ ████ ████████ ██ \n ██ ██ ██████████ ██ ██ ██ ████ \n ██ ██ ████ ████ ████ \n ████████ ██████ ████ ██ ██ \n ████████ \n ██████████████ ████ ████ ██ ████ ████ \n ██ ██ ████████ \n ██ ██████ ██ ██ ██ ██ ██ ██ ██ \n ██ ██████ ██ ██████ ██ ██ \n ██ ██████ ██ ██ ██ ██ ██ ████ ████ \n ██ ██ ████ ████ ██ ██ \n ██████████████ ██████ ██ ██████ \n \n \n \n ";

//Create QR code
var gen = new QRCodeGenerator();
var data = gen.CreateQrCode("A05", QRCodeGenerator.ECCLevel.Q);
var asciiCode = new AsciiQRCode(data).GetGraphic(1);

asciiCode.ShouldBe(targetCode);
}

[Fact]
[Category("QRRenderer/AsciiQRCode")]
public void can_render_ascii_qrcode_without_quietzones()
{
var targetCode = "██████████████ ██ ██ ██████████████\n██ ██ ██ ████ ██ ██\n██ ██████ ██ ██ ██ ██ ██ ██████ ██\n██ ██████ ██ ██ ██ ██████ ██\n██ ██████ ██ ██ ██ ██████ ██\n██ ██ ████████ ██ ██\n██████████████ ██ ██ ██ ██████████████\n ██ ████ \n██████████ ████ ████████ ██ ████ \n████ ██ ██ ████ ████████ ██\n ██ ██ ██████████ ██ ██ ██ ████ \n██ ██ ████ ████ ████ \n ████████ ██████ ████ ██ ██\n ████████ \n██████████████ ████ ████ ██ ████ ████\n██ ██ ████████ \n██ ██████ ██ ██ ██ ██ ██ ██ ██\n██ ██████ ██ ██████ ██ ██ \n██ ██████ ██ ██ ██ ██ ██ ████ ████\n██ ██ ████ ████ ██ ██ \n██████████████ ██████ ██ ██████";

//Create QR code
var gen = new QRCodeGenerator();
var data = gen.CreateQrCode("A05", QRCodeGenerator.ECCLevel.Q);
var asciiCode = new AsciiQRCode(data).GetGraphic(1, drawQuietZones : false);

asciiCode.ShouldBe(targetCode);
}

[Fact]
[Category("QRRenderer/AsciiQRCode")]
public void can_render_ascii_qrcode_with_custom_symbols()
{
var targetCode = " \n \n \n \n \n \n \n \n XXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXX \n XXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXX \n XX XX XXXXXX XX XX XX \n XX XX XXXXXX XX XX XX \n XX XXXXXX XX XXXXXXXX XX XXXXXX XX \n XX XXXXXX XX XXXXXXXX XX XXXXXX XX \n XX XXXXXX XX XXXX XX XXXXXX XX \n XX XXXXXX XX XXXX XX XXXXXX XX \n XX XXXXXX XX XX XX XX XXXXXX XX \n XX XXXXXX XX XX XX XX XXXXXX XX \n XX XX XX XX XX \n XX XX XX XX XX \n XXXXXXXXXXXXXX XX XX XX XXXXXXXXXXXXXX \n XXXXXXXXXXXXXX XX XX XX XXXXXXXXXXXXXX \n XXXXXXXX \n XXXXXXXX \n XX XXXXXX XXXXXX XX XX XX \n XX XXXXXX XXXXXX XX XX XX \n XX XXXXXX XXXX XXXXXXXX XXXXXX XX \n XX XXXXXX XXXX XXXXXXXX XXXXXX XX \n XX XX XX XX XX XX \n XX XX XX XX XX XX \n XX XX XX XX XXXXXX \n XX XX XX XX XXXXXX \n XX XXXXXXXX XXXX XX XXXXXXXX XX \n XX XXXXXXXX XXXX XX XXXXXXXX XX \n XX XXXXXXXX XXXX \n XX XXXXXXXX XXXX \n XXXXXXXXXXXXXX XXXXXXXX XX XXXXXX \n XXXXXXXXXXXXXX XXXXXXXX XX XXXXXX \n XX XX XXXXXX XXXXXXXX \n XX XX XXXXXX XXXXXXXX \n XX XXXXXX XX XX XXXX XX XXXX \n XX XXXXXX XX XX XXXX XX XXXX \n XX XXXXXX XX XXXX XXXXXXXX \n XX XXXXXX XX XXXX XXXXXXXX \n XX XXXXXX XX XX XXXXXXXX XX XXXXXX \n XX XXXXXX XX XX XXXXXXXX XX XXXXXX \n XX XX XX XXXX XX \n XX XX XX XXXX XX \n XXXXXXXXXXXXXX XX XXXXXX XXXX XXXX \n XXXXXXXXXXXXXX XX XXXXXX XXXX XXXX \n \n \n \n \n \n \n \n ";

//Create QR code
var gen = new QRCodeGenerator();
var data = gen.CreateQrCode("A", QRCodeGenerator.ECCLevel.Q);
var asciiCode = new AsciiQRCode(data).GetGraphic(2, "X", " ");

asciiCode.ShouldBe(targetCode);
}

[Fact]
[Category("QRRenderer/AsciiQRCode")]
public void can_instantate_parameterless()
{
var asciiCode = new AsciiQRCode();
asciiCode.ShouldNotBeNull();
asciiCode.ShouldBeOfType<AsciiQRCode>();
}

[Fact]
[Category("QRRenderer/AsciiQRCode")]
public void can_render_ascii_qrcode_from_helper()
{
var targetCode = " \n \n \n \n \n \n \n \n XXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXX \n XXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXX \n XX XX XXXXXX XX XX XX \n XX XX XXXXXX XX XX XX \n XX XXXXXX XX XXXXXXXX XX XXXXXX XX \n XX XXXXXX XX XXXXXXXX XX XXXXXX XX \n XX XXXXXX XX XXXX XX XXXXXX XX \n XX XXXXXX XX XXXX XX XXXXXX XX \n XX XXXXXX XX XX XX XX XXXXXX XX \n XX XXXXXX XX XX XX XX XXXXXX XX \n XX XX XX XX XX \n XX XX XX XX XX \n XXXXXXXXXXXXXX XX XX XX XXXXXXXXXXXXXX \n XXXXXXXXXXXXXX XX XX XX XXXXXXXXXXXXXX \n XXXXXXXX \n XXXXXXXX \n XX XXXXXX XXXXXX XX XX XX \n XX XXXXXX XXXXXX XX XX XX \n XX XXXXXX XXXX XXXXXXXX XXXXXX XX \n XX XXXXXX XXXX XXXXXXXX XXXXXX XX \n XX XX XX XX XX XX \n XX XX XX XX XX XX \n XX XX XX XX XXXXXX \n XX XX XX XX XXXXXX \n XX XXXXXXXX XXXX XX XXXXXXXX XX \n XX XXXXXXXX XXXX XX XXXXXXXX XX \n XX XXXXXXXX XXXX \n XX XXXXXXXX XXXX \n XXXXXXXXXXXXXX XXXXXXXX XX XXXXXX \n XXXXXXXXXXXXXX XXXXXXXX XX XXXXXX \n XX XX XXXXXX XXXXXXXX \n XX XX XXXXXX XXXXXXXX \n XX XXXXXX XX XX XXXX XX XXXX \n XX XXXXXX XX XX XXXX XX XXXX \n XX XXXXXX XX XXXX XXXXXXXX \n XX XXXXXX XX XXXX XXXXXXXX \n XX XXXXXX XX XX XXXXXXXX XX XXXXXX \n XX XXXXXX XX XX XXXXXXXX XX XXXXXX \n XX XX XX XXXX XX \n XX XX XX XXXX XX \n XXXXXXXXXXXXXX XX XXXXXX XXXX XXXX \n XXXXXXXXXXXXXX XX XXXXXX XXXX XXXX \n \n \n \n \n \n \n \n ";

//Create QR code
var gen = new QRCodeGenerator();
var data = gen.CreateQrCode("A", QRCodeGenerator.ECCLevel.Q);
var asciiCode = AsciiQRCodeHelper.GetQRCode("A", 2, "X", " ", QRCodeGenerator.ECCLevel.Q);
asciiCode.ShouldBe(targetCode);
}
}
}