Skip to content

Commit 7bccc6c

Browse files
Shane32gfoidl
andauthored
Split QRCode and ArtQRCode to QRCoder.SystemDrawing (#686)
* Target .NET Standard 2.0, .NET Standard 2.1 and .NET 6.0 * Remove master branch restriction from PR workflow * Add develop branch to CI workflow triggers * Update workflow to remove master branch restriction Removed branch specification for pull request trigger. * Update VersionPrefix to 2.0.0-preview * Don't test .NET Core 2.1 * Remove .NET Core 2.1 and .NET 5.0 from CI workflows * Add QRCoder library classes and methods for QR code generation and payload handling - Implemented abstract class AbstractQRCode and derived classes: ArtQRCode, AsciiQRCode, Base64QRCode, BitmapByteQRCode, PdfByteQRCode, PngByteQRCode, PostscriptQRCode, SvgQRCode, and QRCode. - Added helper classes for each QR code type to facilitate QR code generation. - Introduced PayloadGenerator with various payload types including BezahlCode, BitcoinAddress, CalendarEvent, ContactData, Geolocation, Girocode, and more. - Defined enums for various configurations and options within the QR code generation process. - Included exception handling classes for managing errors related to data size and specific payload types. - Established a comprehensive structure for QR code data management with QRCodeData and QRCodeGenerator classes. * Update * Fix usings * update * update * Split project to QRCoder.SystemDrawing * update * Add additional color names with alternative spellings to ColorTranslator * Add documentation for known HTML color names in ColorTranslator * Refactor GetGraphic method to simplify color handling logic * Refactor GetGraphic method overloads to improve color handling and maintain consistency * Refactor GetGraphic method to enhance functionality and remove redundancy * Refactor GetGraphic method to improve clarity and maintain consistency in overloads * Refactor GetGraphic method to restore and enhance overload with color parameters for improved flexibility * Refactor GetGraphic method to add overload for enhanced color customization and maintain consistency * Update * Update cross-platform support information in README.md * Add migration guide for QRCoder v2 with new features and breaking changes * Add migration guide for QRCoder v2 and update README.md * Update project references and enhance migration documentation for QRCoder v2 * fix usings * update * Update QRCoder/Base64QRCode.cs Co-authored-by: Günther Foidl <[email protected]> * Use ReadOnlySpan * Add newlines --------- Co-authored-by: Günther Foidl <[email protected]>
1 parent 757ea5f commit 7bccc6c

33 files changed

+571
-1282
lines changed
File renamed without changes.
File renamed without changes.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<!-- Set essential properties -->
5+
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
6+
<IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">true</IsTrimmable>
7+
<IsPackable>true</IsPackable>
8+
9+
<!-- Set NuGet package properties -->
10+
<PackageTags>c# csharp qr qrcoder qrcode qr-generator qr-code-generator</PackageTags>
11+
<Description>QRCoder is a simple library, written in C#.NET, which enables you to create QR codes.</Description>
12+
13+
<!-- Set strong name -->
14+
<AssemblyOriginatorKeyFile>../QRCoder/QRCoderStrongName.snk</AssemblyOriginatorKeyFile>
15+
</PropertyGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="System.Drawing.Common" Version="4.7.3" Condition="'$(TargetFramework)' != 'net6.0'" />
19+
<PackageReference Include="System.Drawing.Common" Version="6.0.0" Condition="'$(TargetFramework)' == 'net6.0'" />
20+
</ItemGroup>
21+
22+
<ItemGroup>
23+
<ProjectReference Include="..\QRCoder\QRCoder.csproj" />
24+
</ItemGroup>
25+
26+
</Project>

QRCoder.sln

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
3131
EndProject
3232
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QRCoderSamples", "QRCoderSamples\QRCoderSamples.csproj", "{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}"
3333
EndProject
34+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QRCoder.SystemDrawing", "QRCoder.SystemDrawing\QRCoder.SystemDrawing.csproj", "{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}"
35+
EndProject
3436
Global
3537
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3638
Debug|Any CPU = Debug|Any CPU
@@ -201,6 +203,22 @@ Global
201203
{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}.Release|x64.Build.0 = Release|Any CPU
202204
{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}.Release|x86.ActiveCfg = Release|Any CPU
203205
{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}.Release|x86.Build.0 = Release|Any CPU
206+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
207+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
208+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|ARM.ActiveCfg = Debug|Any CPU
209+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|ARM.Build.0 = Debug|Any CPU
210+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x64.ActiveCfg = Debug|Any CPU
211+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x64.Build.0 = Debug|Any CPU
212+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x86.ActiveCfg = Debug|Any CPU
213+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x86.Build.0 = Debug|Any CPU
214+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
215+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|Any CPU.Build.0 = Release|Any CPU
216+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|ARM.ActiveCfg = Release|Any CPU
217+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|ARM.Build.0 = Release|Any CPU
218+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x64.ActiveCfg = Release|Any CPU
219+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x64.Build.0 = Release|Any CPU
220+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x86.ActiveCfg = Release|Any CPU
221+
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x86.Build.0 = Release|Any CPU
204222
EndGlobalSection
205223
GlobalSection(SolutionProperties) = preSolution
206224
HideSolutionNode = FALSE

QRCoder/Base64QRCode.cs

Lines changed: 48 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Drawing;
2-
using System.Drawing.Imaging;
32
using System.Runtime.InteropServices;
43
using static QRCoder.Base64QRCode;
54
using static QRCoder.QRCodeGenerator;
@@ -35,6 +34,17 @@ public Base64QRCode(QRCodeData data) : base(data)
3534
public string GetGraphic(int pixelsPerModule)
3635
=> GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
3736

37+
/// <summary>
38+
/// Returns a base64-encoded string that contains the resulting QR code as a PNG image.
39+
/// </summary>
40+
/// <param name="pixelsPerModule">The number of pixels each dark/light module of the QR code will occupy in the final QR code image.</param>
41+
/// <param name="darkColorHtmlHex">The color of the dark modules in HTML hex format.</param>
42+
/// <param name="lightColorHtmlHex">The color of the light modules in HTML hex format.</param>
43+
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
44+
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
45+
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true)
46+
=> GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), drawQuietZones);
47+
3848
/// <summary>
3949
/// Returns a base64-encoded string that contains the resulting QR code as an image.
4050
/// </summary>
@@ -44,7 +54,8 @@ public string GetGraphic(int pixelsPerModule)
4454
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
4555
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
4656
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
47-
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
57+
[Obsolete("The imgType parameter is obsolete. Only PNG format is supported. Use the overload without the imgType parameter.")]
58+
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones, ImageType imgType)
4859
=> GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), drawQuietZones, imgType);
4960

5061
/// <summary>
@@ -56,121 +67,80 @@ public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string li
5667
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
5768
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
5869
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
59-
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
70+
[Obsolete("The imgType parameter is obsolete. Only PNG format is supported. Use the overload without the imgType parameter.")]
71+
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones, ImageType imgType)
6072
{
61-
if (imgType == ImageType.Png)
73+
if (imgType != ImageType.Png)
6274
{
63-
var pngCoder = new PngByteQRCode(QrCodeData);
64-
65-
byte[] pngData;
66-
if (darkColor == Color.Black && lightColor == Color.White)
67-
{
68-
pngData = pngCoder.GetGraphic(pixelsPerModule, drawQuietZones);
69-
}
70-
else
71-
{
72-
byte[] darkColorBytes;
73-
byte[] lightColorBytes;
74-
if (darkColor.A != 255 || lightColor.A != 255)
75-
{
76-
darkColorBytes = new byte[] { darkColor.R, darkColor.G, darkColor.B, darkColor.A };
77-
lightColorBytes = new byte[] { lightColor.R, lightColor.G, lightColor.B, lightColor.A };
78-
}
79-
else
80-
{
81-
darkColorBytes = new byte[] { darkColor.R, darkColor.G, darkColor.B };
82-
lightColorBytes = new byte[] { lightColor.R, lightColor.G, lightColor.B };
83-
}
84-
pngData = pngCoder.GetGraphic(pixelsPerModule, darkColorBytes, lightColorBytes, drawQuietZones);
85-
}
86-
87-
return Convert.ToBase64String(pngData, Base64FormattingOptions.None);
75+
throw new NotSupportedException($"Only PNG format is supported. {imgType} format is no longer supported.");
8876
}
8977

90-
#pragma warning disable CA1416 // Validate platform compatibility
91-
var qr = new QRCode(QrCodeData);
92-
var base64 = string.Empty;
93-
using (var bmp = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones))
94-
{
95-
base64 = BitmapToBase64(bmp, imgType);
96-
}
97-
return base64;
98-
#pragma warning restore CA1416 // Validate platform compatibility
78+
return GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones);
9979
}
10080

10181
/// <summary>
102-
/// Returns a base64-encoded string that contains the resulting QR code as an image with an embedded icon.
82+
/// Returns a base64-encoded string that contains the resulting QR code as a PNG image.
10383
/// </summary>
10484
/// <param name="pixelsPerModule">The number of pixels each dark/light module of the QR code will occupy in the final QR code image.</param>
10585
/// <param name="darkColor">The color of the dark modules.</param>
10686
/// <param name="lightColor">The color of the light modules.</param>
107-
/// <param name="icon">The icon to embed in the center of the QR code.</param>
108-
/// <param name="iconSizePercent">The size of the icon as a percentage of the QR code.</param>
109-
/// <param name="iconBorderWidth">The width of the border around the icon.</param>
11087
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
111-
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
11288
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
113-
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
114-
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Bitmap icon, int iconSizePercent = 15, int iconBorderWidth = 6, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
89+
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true)
11590
{
116-
var qr = new QRCode(QrCodeData);
117-
var base64 = string.Empty;
118-
using (var bmp = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, icon, iconSizePercent, iconBorderWidth, drawQuietZones))
119-
{
120-
base64 = BitmapToBase64(bmp, imgType);
121-
}
122-
return base64;
123-
}
124-
125-
/// <summary>
126-
/// Converts a bitmap to a base64-encoded string.
127-
/// </summary>
128-
/// <param name="bmp">The bitmap to convert.</param>
129-
/// <param name="imgType">The type of image (PNG, JPEG, GIF).</param>
130-
/// <returns>Returns the base64-encoded string representation of the bitmap.</returns>
131-
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
132-
private static string BitmapToBase64(Bitmap bmp, ImageType imgType)
133-
{
134-
var iFormat = imgType switch
135-
{
136-
ImageType.Png => ImageFormat.Png,
137-
ImageType.Jpeg => ImageFormat.Jpeg,
138-
ImageType.Gif => ImageFormat.Gif,
139-
_ => ImageFormat.Png,
140-
};
141-
using var memoryStream = new MemoryStream();
142-
bmp.Save(memoryStream, iFormat);
143-
return Convert.ToBase64String(memoryStream.ToArray(), Base64FormattingOptions.None);
91+
using var pngCoder = new PngByteQRCode(QrCodeData);
92+
var pngData = pngCoder.GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones);
93+
return Convert.ToBase64String(pngData, Base64FormattingOptions.None);
14494
}
14595

14696
/// <summary>
14797
/// Specifies the type of image to generate.
14898
/// </summary>
99+
[Obsolete("ImageType enum is obsolete. Only PNG format is supported.")]
149100
public enum ImageType
150101
{
151102
/// <summary>
152103
/// Graphics Interchange Format (GIF) image format, a bitmap image format with limited color support
153104
/// </summary>
154-
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
155105
Gif,
156106
/// <summary>
157107
/// Joint Photographic Experts Group (JPEG) image format, a lossy compressed image format
158108
/// </summary>
159-
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
160109
Jpeg,
161110
/// <summary>
162111
/// Portable Network Graphics (PNG) image format, a lossless raster graphics format
163112
/// </summary>
164113
Png
165114
}
166-
167115
}
168116

169117
/// <summary>
170118
/// Provides static methods for creating base64-encoded QR codes.
171119
/// </summary>
172120
public static class Base64QRCodeHelper
173121
{
122+
/// <summary>
123+
/// Creates a base64-encoded QR code as a one-shot operation.
124+
/// </summary>
125+
/// <param name="plainText">The text or payload to be encoded inside the QR code.</param>
126+
/// <param name="pixelsPerModule">The number of pixels each dark/light module of the QR code will occupy in the final QR code image.</param>
127+
/// <param name="darkColorHtmlHex">The color of the dark modules in HTML hex format.</param>
128+
/// <param name="lightColorHtmlHex">The color of the light modules in HTML hex format.</param>
129+
/// <param name="eccLevel">The level of error correction data.</param>
130+
/// <param name="forceUtf8">Specifies whether the generator should be forced to work in UTF-8 mode.</param>
131+
/// <param name="utf8BOM">Specifies whether the byte-order-mark should be used.</param>
132+
/// <param name="eciMode">Specifies which ECI mode should be used.</param>
133+
/// <param name="requestedVersion">Sets the fixed QR code target version.</param>
134+
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
135+
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
136+
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, bool drawQuietZones = true)
137+
{
138+
using var qrGenerator = new QRCodeGenerator();
139+
using var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion);
140+
using var qrCode = new Base64QRCode(qrCodeData);
141+
return qrCode.GetGraphic(pixelsPerModule, darkColorHtmlHex, lightColorHtmlHex, drawQuietZones);
142+
}
143+
174144
/// <summary>
175145
/// Creates a base64-encoded QR code with a single function call.
176146
/// </summary>
@@ -186,7 +156,8 @@ public static class Base64QRCodeHelper
186156
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
187157
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
188158
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
189-
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
159+
[Obsolete("The imgType parameter is obsolete. Only PNG format is supported. Use the overload without the imgType parameter.")]
160+
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, ECCLevel eccLevel, bool forceUtf8, bool utf8BOM, EciMode eciMode, int requestedVersion, bool drawQuietZones, ImageType imgType)
190161
{
191162
using var qrGenerator = new QRCodeGenerator();
192163
using var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion);

0 commit comments

Comments
 (0)