Skip to content

Commit efc73cf

Browse files
authored
Merge pull request #384 from hbdbim/master
ASCIQRCode Small
2 parents e094cd3 + 80fd288 commit efc73cf

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

QRCoder/ASCIIQRCode.cs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,29 @@ public AsciiQRCode(QRCodeData data) : base(data) { }
1616

1717

1818
/// <summary>
19-
/// Returns a strings that contains the resulting QR code as ASCII chars.
19+
/// Returns a strings that contains the resulting QR code as textual representation.
2020
/// </summary>
2121
/// <param name="repeatPerModule">Number of repeated darkColorString/whiteSpaceString per module.</param>
2222
/// <param name="darkColorString">String for use as dark color modules. In case of string make sure whiteSpaceString has the same length.</param>
2323
/// <param name="whiteSpaceString">String for use as white modules (whitespace). In case of string make sure darkColorString has the same length.</param>
24+
/// <param name="drawQuietZones">Bool that defines if quiet zones around the QR code shall be drawn</param>
2425
/// <param name="endOfLine">End of line separator. (Default: \n)</param>
2526
/// <returns></returns>
2627
public string GetGraphic(int repeatPerModule, string darkColorString = "██", string whiteSpaceString = " ", bool drawQuietZones = true, string endOfLine = "\n")
2728
{
29+
if (repeatPerModule < 1)
30+
throw new Exception("The repeatPerModule-parameter must be 1 or greater.");
2831
return string.Join(endOfLine, GetLineByLineGraphic(repeatPerModule, darkColorString, whiteSpaceString, drawQuietZones));
2932
}
30-
33+
3134

3235
/// <summary>
3336
/// Returns an array of strings that contains each line of the resulting QR code as ASCII chars.
3437
/// </summary>
3538
/// <param name="repeatPerModule">Number of repeated darkColorString/whiteSpaceString per module.</param>
3639
/// <param name="darkColorString">String for use as dark color modules. In case of string make sure whiteSpaceString has the same length.</param>
3740
/// <param name="whiteSpaceString">String for use as white modules (whitespace). In case of string make sure darkColorString has the same length.</param>
41+
/// <param name="drawQuietZones">Bool that defines if quiet zones around the QR code shall be drawn</param>
3842
/// <returns></returns>
3943
public string[] GetLineByLineGraphic(int repeatPerModule, string darkColorString = "██", string whiteSpaceString = " ", bool drawQuietZones = true)
4044
{
@@ -62,6 +66,61 @@ public string[] GetLineByLineGraphic(int repeatPerModule, string darkColorString
6266
}
6367
return qrCode.ToArray();
6468
}
69+
70+
/// <summary>
71+
/// Returns a strings that contains the resulting QR code as minified textual representation.
72+
/// </summary>
73+
/// <param name="drawQuietZones">Bool that defines if quiet zones around the QR code shall be drawn</param>
74+
/// <param name="invert">If set to true, dark and light colors will be inverted</param>
75+
/// <param name="endOfLine">End of line separator. (Default: \n)</param>
76+
/// <returns></returns>
77+
public string GetGraphicSmall(bool drawQuietZones = true, bool invert = false, string endOfLine = "\n")
78+
{
79+
bool BLACK = true, WHITE = false;
80+
81+
var palette = new
82+
{
83+
WHITE_ALL = "\u2588",
84+
WHITE_BLACK = "\u2580",
85+
BLACK_WHITE = "\u2584",
86+
BLACK_ALL = " ",
87+
};
88+
89+
var moduleData = QrCodeData.ModuleMatrix;
90+
var sbSize = (moduleData.Count + endOfLine.Length) * (int)Math.Ceiling(moduleData.Count / 2.0) - 1;
91+
var lineBuilder = new StringBuilder(sbSize);
92+
93+
var quietZonesModifier = (drawQuietZones ? 0 : 8);
94+
var quietZonesOffset = (int)(quietZonesModifier * 0.5);
95+
var sideLength = (moduleData.Count - quietZonesModifier);
96+
97+
for (var row = 0; row < sideLength; row += 2)
98+
{
99+
for (var col = 0; col < sideLength; col++)
100+
{
101+
var current = moduleData[col + quietZonesOffset][row + quietZonesOffset] ^ invert;
102+
var nextRowId = row + quietZonesOffset + 1;
103+
104+
// Set next to whitespace "color"
105+
var next = BLACK;
106+
// Fill next with value, if in data range
107+
if (nextRowId < QrCodeData.ModuleMatrix.Count)
108+
next = moduleData[col + quietZonesOffset][nextRowId] ^ invert;
109+
110+
if (current == WHITE && next == WHITE)
111+
lineBuilder.Append(palette.WHITE_ALL);
112+
else if (current == WHITE && next == BLACK)
113+
lineBuilder.Append(palette.WHITE_BLACK);
114+
else if (current == BLACK && next == WHITE)
115+
lineBuilder.Append(palette.BLACK_WHITE);
116+
else
117+
lineBuilder.Append(palette.BLACK_ALL);
118+
}
119+
if (row + 2 < sideLength)
120+
lineBuilder.Append(endOfLine);
121+
}
122+
return lineBuilder.ToString();
123+
}
65124
}
66125

67126

@@ -74,5 +133,13 @@ public static string GetQRCode(string plainText, int pixelsPerModule, string dar
74133
using (var qrCode = new AsciiQRCode(qrCodeData))
75134
return qrCode.GetGraphic(pixelsPerModule, darkColorString, whiteSpaceString, drawQuietZones, endOfLine);
76135
}
136+
137+
public static string GetQRCode(string plainText, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, string endOfLine = "\n", bool drawQuietZones = true, bool invert = true)
138+
{
139+
using (var qrGenerator = new QRCodeGenerator())
140+
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
141+
using (var qrCode = new AsciiQRCode(qrCodeData))
142+
return qrCode.GetGraphicSmall(drawQuietZones, invert, endOfLine);
143+
}
77144
}
78145
}

QRCoderTests/AsciiQRCodeRendererTests.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,62 @@ public void can_render_ascii_qrcode()
2424
asciiCode.ShouldBe(targetCode);
2525
}
2626

27+
[Fact]
28+
[Category("QRRenderer/AsciiQRCode")]
29+
public void can_render_small_ascii_qrcode()
30+
{
31+
var targetCode = "█████████████████████████████\n█████████████████████████████\n████ ▄▄▄▄▄ █▀▄█ ▀█ ▄▄▄▄▄ ████\n████ █ █ █▄█ █▄█ █ █ ████\n████ █▄▄▄█ █▄▀▀▀▀█ █▄▄▄█ ████\n████▄▄▄▄▄▄▄█ █ ▀▄█▄▄▄▄▄▄▄████\n████ ▄▄ █▄ ██▀ ▄▄▄▀ ▀ ▄▀████\n████▀█▄█ █▄ ▄ ▀▄▀ █▄█▄▄█████\n█████▄▄▄▄█▄▄▄████▀▀ █▄█▄████\n████ ▄▄▄▄▄ █▄▄█▄▄▀ ▀ ▄█▄▄████\n████ █ █ █ ▀ █▄▀█ ██▄█▄████\n████ █▄▄▄█ █ ▀▄▀ █▄█▄ █ ▄████\n████▄▄▄▄▄▄▄█▄▄▄█████▄█▄▄▄████\n█████████████████████████████\n▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀";
32+
33+
//Create QR code
34+
var gen = new QRCodeGenerator();
35+
var data = gen.CreateQrCode("A05", QRCodeGenerator.ECCLevel.Q);
36+
var asciiCode = new AsciiQRCode(data).GetGraphicSmall();
37+
38+
asciiCode.ShouldBe(targetCode);
39+
}
40+
41+
[Fact]
42+
[Category("QRRenderer/AsciiQRCode")]
43+
public void can_render_small_ascii_qrcode_without_quietzones()
44+
{
45+
var targetCode = " ▄▄▄▄▄ █▀▄█ ▀█ ▄▄▄▄▄ \n █ █ █▄█ █▄█ █ █ \n █▄▄▄█ █▄▀▀▀▀█ █▄▄▄█ \n▄▄▄▄▄▄▄█ █ ▀▄█▄▄▄▄▄▄▄\n ▄▄ █▄ ██▀ ▄▄▄▀ ▀ ▄▀\n▀█▄█ █▄ ▄ ▀▄▀ █▄█▄▄█\n█▄▄▄▄█▄▄▄████▀▀ █▄█▄\n ▄▄▄▄▄ █▄▄█▄▄▀ ▀ ▄█▄▄\n █ █ █ ▀ █▄▀█ ██▄█▄\n █▄▄▄█ █ ▀▄▀ █▄█▄ █ ▄\n▄▄▄▄▄▄▄█▄▄▄█████▄█▄▄▄";
46+
47+
//Create QR code
48+
var gen = new QRCodeGenerator();
49+
var data = gen.CreateQrCode("A05", QRCodeGenerator.ECCLevel.Q);
50+
var asciiCode = new AsciiQRCode(data).GetGraphicSmall(drawQuietZones: false);
51+
52+
asciiCode.ShouldBe(targetCode);
53+
}
54+
55+
[Fact]
56+
[Category("QRRenderer/AsciiQRCode")]
57+
public void can_render_small_ascii_qrcode_inverted()
58+
{
59+
var targetCode = " \n \n █▀▀▀▀▀█ ▄▀ █▄ █▀▀▀▀▀█ \n █ ███ █ ▀ █ ▀ █ ███ █ \n █ ▀▀▀ █ ▀▄▄▄▄ █ ▀▀▀ █ \n ▀▀▀▀▀▀▀ █ █▄▀ ▀▀▀▀▀▀▀ \n ██▀▀█ ▀█ ▄█▀▀▀▄█▄█▀▄ \n ▄ ▀ █ ▀██▀█▄▀▄█ ▀ ▀▀ \n ▀▀▀▀ ▀▀▀ ▄▄██ ▀ ▀ \n █▀▀▀▀▀█ ▀▀ ▀▀▄█▄█▀ ▀▀ \n █ ███ █ █▄█ ▀▄ █ ▀ ▀ \n █ ▀▀▀ █ █▄▀▄█ ▀ ▀█ █▀ \n ▀▀▀▀▀▀▀ ▀▀▀ ▀ ▀▀▀ \n \n ";
60+
61+
//Create QR code
62+
var gen = new QRCodeGenerator();
63+
var data = gen.CreateQrCode("A05", QRCodeGenerator.ECCLevel.Q);
64+
var asciiCode = new AsciiQRCode(data).GetGraphicSmall(invert: true);
65+
66+
asciiCode.ShouldBe(targetCode);
67+
}
68+
69+
[Fact]
70+
[Category("QRRenderer/AsciiQRCode")]
71+
public void can_render_small_ascii_qrcode_with_custom_eol()
72+
{
73+
var targetCode = "█████████████████████████████\r\n█████████████████████████████\r\n████ ▄▄▄▄▄ █▀▄█ ▀█ ▄▄▄▄▄ ████\r\n████ █ █ █▄█ █▄█ █ █ ████\r\n████ █▄▄▄█ █▄▀▀▀▀█ █▄▄▄█ ████\r\n████▄▄▄▄▄▄▄█ █ ▀▄█▄▄▄▄▄▄▄████\r\n████ ▄▄ █▄ ██▀ ▄▄▄▀ ▀ ▄▀████\r\n████▀█▄█ █▄ ▄ ▀▄▀ █▄█▄▄█████\r\n█████▄▄▄▄█▄▄▄████▀▀ █▄█▄████\r\n████ ▄▄▄▄▄ █▄▄█▄▄▀ ▀ ▄█▄▄████\r\n████ █ █ █ ▀ █▄▀█ ██▄█▄████\r\n████ █▄▄▄█ █ ▀▄▀ █▄█▄ █ ▄████\r\n████▄▄▄▄▄▄▄█▄▄▄█████▄█▄▄▄████\r\n█████████████████████████████\r\n▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀";
74+
75+
//Create QR code
76+
var gen = new QRCodeGenerator();
77+
var data = gen.CreateQrCode("A05", QRCodeGenerator.ECCLevel.Q);
78+
var asciiCode = new AsciiQRCode(data).GetGraphicSmall(endOfLine: "\r\n");
79+
80+
asciiCode.ShouldBe(targetCode);
81+
}
82+
2783
[Fact]
2884
[Category("QRRenderer/AsciiQRCode")]
2985
public void can_render_ascii_qrcode_without_quietzones()

0 commit comments

Comments
 (0)