Skip to content

Commit 4a10c16

Browse files
authored
Add path-based SVG rendering with RLE encoding to reduce file size and memory usage (#655)
* Optimize SVGs * Apply suggestion from coderabbit * Use invariant culture * fix * Update * Fix * Add test for new method * Add tests * Final comment updates * update * update comment * Convert to regular string * Add invariant culture formatting methods for StringBuilder appends * Update AppendInvariant method to use G7 precision for float formatting * Update ToStr method to use G7 precision for float formatting
1 parent 696bb39 commit 4a10c16

File tree

24 files changed

+450
-2751
lines changed

24 files changed

+450
-2751
lines changed

QRCoder/Extensions/StringExtensions.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,48 @@ internal static byte[] HexColorToByteArray(this string colorString)
5555
internal static string ToString(this char c, CultureInfo _)
5656
=> c.ToString();
5757
#endif
58+
59+
/// <summary>
60+
/// Appends an integer value to the StringBuilder using invariant culture formatting.
61+
/// </summary>
62+
/// <param name="sb">The StringBuilder to append to.</param>
63+
/// <param name="num">The integer value to append.</param>
64+
internal static void AppendInvariant(this StringBuilder sb, int num)
65+
{
66+
#if NET6_0_OR_GREATER
67+
sb.Append(CultureInfo.InvariantCulture, $"{num}");
68+
#else
69+
#if HAS_SPAN
70+
Span<char> buffer = stackalloc char[16];
71+
if (num.TryFormat(buffer, out int charsWritten, default, CultureInfo.InvariantCulture))
72+
{
73+
sb.Append(buffer.Slice(0, charsWritten));
74+
return;
75+
}
76+
#endif
77+
sb.Append(num.ToString(CultureInfo.InvariantCulture));
78+
#endif
79+
}
80+
81+
/// <summary>
82+
/// Appends a float value to the StringBuilder using invariant culture formatting with G7 precision.
83+
/// </summary>
84+
/// <param name="sb">The StringBuilder to append to.</param>
85+
/// <param name="num">The float value to append.</param>
86+
internal static void AppendInvariant(this StringBuilder sb, float num)
87+
{
88+
#if NET6_0_OR_GREATER
89+
sb.Append(CultureInfo.InvariantCulture, $"{num:G7}");
90+
#else
91+
#if HAS_SPAN
92+
Span<char> buffer = stackalloc char[16];
93+
if (num.TryFormat(buffer, out int charsWritten, "G7", CultureInfo.InvariantCulture))
94+
{
95+
sb.Append(buffer.Slice(0, charsWritten));
96+
return;
97+
}
98+
#endif
99+
sb.Append(num.ToString("G7", CultureInfo.InvariantCulture));
100+
#endif
101+
}
58102
}

QRCoder/PdfByteQRCode.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,11 @@ private string CreatePathFromModules()
204204

205205
// Create a single rectangle for the entire run of dark modules
206206
// Format: x y width height re
207-
pathCommands.Append(ToStr(startX));
207+
pathCommands.AppendInvariant(startX);
208208
pathCommands.Append(' ');
209-
pathCommands.Append(ToStr(y));
209+
pathCommands.AppendInvariant(y);
210210
pathCommands.Append(' ');
211-
pathCommands.Append(ToStr(x - startX));
211+
pathCommands.AppendInvariant(x - startX);
212212
pathCommands.Append(" 1 re\r\n");
213213
}
214214
}
@@ -242,11 +242,11 @@ private static string ColorToPdfRgb(byte[] color)
242242
private static string ToStr(int value) => value.ToString(CultureInfo.InvariantCulture);
243243

244244
/// <summary>
245-
/// Converts an integer to a string using invariant culture for consistent PDF formatting.
245+
/// Converts a float to a string using invariant culture for consistent PDF formatting.
246246
/// </summary>
247-
/// <param name="value">The integer value to convert.</param>
248-
/// <returns>String representation of the integer.</returns>
249-
private static string ToStr(float value) => value.ToString("0.######", CultureInfo.InvariantCulture);
247+
/// <param name="value">The float value to convert.</param>
248+
/// <returns>String representation of the float.</returns>
249+
private static string ToStr(float value) => value.ToString("G7", CultureInfo.InvariantCulture);
250250
}
251251

252252
/// <summary>

QRCoder/SvgQRCode.cs

Lines changed: 270 additions & 111 deletions
Large diffs are not rendered by default.

QRCoderApiTests/net35+net40+net50+netstandard20+netstandard21/QRCoder.approved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,7 @@ namespace QRCoder
952952
{
953953
public SvgQRCode() { }
954954
public SvgQRCode(QRCoder.QRCodeData data) { }
955+
public string GetGraphic() { }
955956
public string GetGraphic(int pixelsPerModule) { }
956957
public string GetGraphic(System.Drawing.Size viewBox, bool drawQuietZones = true, QRCoder.SvgQRCode.SizingMode sizingMode = 0, QRCoder.SvgQRCode.SvgLogo? logo = null) { }
957958
public string GetGraphic(System.Drawing.Size viewBox, System.Drawing.Color darkColor, System.Drawing.Color lightColor, bool drawQuietZones = true, QRCoder.SvgQRCode.SizingMode sizingMode = 0, QRCoder.SvgQRCode.SvgLogo? logo = null) { }

QRCoderApiTests/net60/QRCoder.approved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,7 @@ namespace QRCoder
959959
{
960960
public SvgQRCode() { }
961961
public SvgQRCode(QRCoder.QRCodeData data) { }
962+
public string GetGraphic() { }
962963
public string GetGraphic(int pixelsPerModule) { }
963964
public string GetGraphic(System.Drawing.Size viewBox, bool drawQuietZones = true, QRCoder.SvgQRCode.SizingMode sizingMode = 0, QRCoder.SvgQRCode.SvgLogo? logo = null) { }
964965
public string GetGraphic(System.Drawing.Size viewBox, System.Drawing.Color darkColor, System.Drawing.Color lightColor, bool drawQuietZones = true, QRCoder.SvgQRCode.SizingMode sizingMode = 0, QRCoder.SvgQRCode.SvgLogo? logo = null) { }

QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode.approved.svg

Lines changed: 3 additions & 226 deletions
Loading
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 3 additions & 77 deletions
Loading

0 commit comments

Comments
 (0)