Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
90f3347
Target .NET Standard 2.0, .NET Standard 2.1 and .NET 6.0
Shane32 Oct 18, 2025
cee10c3
Remove master branch restriction from PR workflow
Shane32 Oct 18, 2025
733f3c1
Add develop branch to CI workflow triggers
Shane32 Oct 18, 2025
d20feaf
Update workflow to remove master branch restriction
Shane32 Oct 18, 2025
429f8e8
Update VersionPrefix to 2.0.0-preview
Shane32 Oct 18, 2025
d5b1a92
Don't test .NET Core 2.1
Shane32 Oct 18, 2025
07894bb
Remove .NET Core 2.1 and .NET 5.0 from CI workflows
Shane32 Oct 18, 2025
232723b
Add QRCoder library classes and methods for QR code generation and pa…
Shane32 Oct 18, 2025
8eced06
Update
Shane32 Oct 18, 2025
3f8a9f7
Fix usings
Shane32 Oct 18, 2025
38ef897
update
Shane32 Oct 18, 2025
d6b1ca5
update
Shane32 Oct 18, 2025
3b3ceb2
Split project to QRCoder.SystemDrawing
Shane32 Oct 19, 2025
3dab082
update
Shane32 Oct 19, 2025
2db52d0
Add additional color names with alternative spellings to ColorTranslator
Shane32 Oct 19, 2025
7070bcc
Add documentation for known HTML color names in ColorTranslator
Shane32 Oct 19, 2025
1f7fcb4
Refactor GetGraphic method to simplify color handling logic
Shane32 Oct 19, 2025
40d3e4f
Refactor GetGraphic method overloads to improve color handling and ma…
Shane32 Oct 19, 2025
2336548
Refactor GetGraphic method to enhance functionality and remove redund…
Shane32 Oct 19, 2025
6f82b7c
Refactor GetGraphic method to improve clarity and maintain consistenc…
Shane32 Oct 19, 2025
593c44c
Refactor GetGraphic method to restore and enhance overload with color…
Shane32 Oct 19, 2025
62f6ddd
Refactor GetGraphic method to add overload for enhanced color customi…
Shane32 Oct 19, 2025
ec94c43
Update
Shane32 Oct 19, 2025
252d8dd
Update cross-platform support information in README.md
Shane32 Oct 19, 2025
2703bcf
Merge branch 'tfm' into systemdrawing
Shane32 Oct 19, 2025
68880f5
Add migration guide for QRCoder v2 with new features and breaking cha…
Shane32 Oct 19, 2025
564826a
Add migration guide for QRCoder v2 and update README.md
Shane32 Oct 19, 2025
31734e1
Merge branch 'tfm' into systemdrawing
Shane32 Oct 19, 2025
695ab8b
Update project references and enhance migration documentation for QRC…
Shane32 Oct 19, 2025
18c2f77
fix usings
Shane32 Oct 19, 2025
5cf388d
update
Shane32 Oct 19, 2025
f6d19cd
Update QRCoder/Base64QRCode.cs
Shane32 Oct 25, 2025
d8b1b58
Use ReadOnlySpan
Shane32 Oct 25, 2025
7e70143
Merge branch 'tfm' into systemdrawing
Shane32 Oct 25, 2025
e1cbf15
Add newlines
Shane32 Oct 25, 2025
b59a83d
Merge from develop
Shane32 Oct 25, 2025
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
File renamed without changes.
File renamed without changes.
26 changes: 26 additions & 0 deletions QRCoder.SystemDrawing/QRCoder.SystemDrawing.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- Set essential properties -->
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">true</IsTrimmable>
<IsPackable>true</IsPackable>

<!-- Set NuGet package properties -->
<PackageTags>c# csharp qr qrcoder qrcode qr-generator qr-code-generator</PackageTags>
<Description>QRCoder is a simple library, written in C#.NET, which enables you to create QR codes.</Description>

<!-- Set strong name -->
<AssemblyOriginatorKeyFile>../QRCoder/QRCoderStrongName.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="4.7.3" Condition="'$(TargetFramework)' != 'net6.0'" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" Condition="'$(TargetFramework)' == 'net6.0'" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\QRCoder\QRCoder.csproj" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions QRCoder.sln
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QRCoderSamples", "QRCoderSamples\QRCoderSamples.csproj", "{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QRCoder.SystemDrawing", "QRCoder.SystemDrawing\QRCoder.SystemDrawing.csproj", "{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -201,6 +203,22 @@ Global
{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}.Release|x64.Build.0 = Release|Any CPU
{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}.Release|x86.ActiveCfg = Release|Any CPU
{61ED615B-C22C-5E3E-DAAD-A77A820E16DF}.Release|x86.Build.0 = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|ARM.ActiveCfg = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|ARM.Build.0 = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x64.ActiveCfg = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x64.Build.0 = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x86.ActiveCfg = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Debug|x86.Build.0 = Debug|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|Any CPU.Build.0 = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|ARM.ActiveCfg = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|ARM.Build.0 = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x64.ActiveCfg = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x64.Build.0 = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x86.ActiveCfg = Release|Any CPU
{FEE6DC1D-BE5A-4498-A70D-35C516AD13F3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
125 changes: 48 additions & 77 deletions QRCoder/Base64QRCode.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using static QRCoder.Base64QRCode;
using static QRCoder.QRCodeGenerator;
Expand Down Expand Up @@ -35,6 +34,17 @@ public Base64QRCode(QRCodeData data) : base(data)
public string GetGraphic(int pixelsPerModule)
=> GetGraphic(pixelsPerModule, Color.Black, Color.White, true);

/// <summary>
/// Returns a base64-encoded string that contains the resulting QR code as a PNG image.
/// </summary>
/// <param name="pixelsPerModule">The number of pixels each dark/light module of the QR code will occupy in the final QR code image.</param>
/// <param name="darkColorHtmlHex">The color of the dark modules in HTML hex format.</param>
/// <param name="lightColorHtmlHex">The color of the light modules in HTML hex format.</param>
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true)
=> GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), drawQuietZones);

/// <summary>
/// Returns a base64-encoded string that contains the resulting QR code as an image.
/// </summary>
Expand All @@ -44,7 +54,8 @@ public string GetGraphic(int pixelsPerModule)
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
[Obsolete("The imgType parameter is obsolete. Only PNG format is supported. Use the overload without the imgType parameter.")]
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones, ImageType imgType)
=> GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), drawQuietZones, imgType);

/// <summary>
Expand All @@ -56,121 +67,80 @@ public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string li
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
[Obsolete("The imgType parameter is obsolete. Only PNG format is supported. Use the overload without the imgType parameter.")]
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones, ImageType imgType)
{
if (imgType == ImageType.Png)
if (imgType != ImageType.Png)
{
var pngCoder = new PngByteQRCode(QrCodeData);

byte[] pngData;
if (darkColor == Color.Black && lightColor == Color.White)
{
pngData = pngCoder.GetGraphic(pixelsPerModule, drawQuietZones);
}
else
{
byte[] darkColorBytes;
byte[] lightColorBytes;
if (darkColor.A != 255 || lightColor.A != 255)
{
darkColorBytes = new byte[] { darkColor.R, darkColor.G, darkColor.B, darkColor.A };
lightColorBytes = new byte[] { lightColor.R, lightColor.G, lightColor.B, lightColor.A };
}
else
{
darkColorBytes = new byte[] { darkColor.R, darkColor.G, darkColor.B };
lightColorBytes = new byte[] { lightColor.R, lightColor.G, lightColor.B };
}
pngData = pngCoder.GetGraphic(pixelsPerModule, darkColorBytes, lightColorBytes, drawQuietZones);
}

return Convert.ToBase64String(pngData, Base64FormattingOptions.None);
throw new NotSupportedException($"Only PNG format is supported. {imgType} format is no longer supported.");
}

#pragma warning disable CA1416 // Validate platform compatibility
var qr = new QRCode(QrCodeData);
var base64 = string.Empty;
using (var bmp = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones))
{
base64 = BitmapToBase64(bmp, imgType);
}
return base64;
#pragma warning restore CA1416 // Validate platform compatibility
return GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones);
}

/// <summary>
/// Returns a base64-encoded string that contains the resulting QR code as an image with an embedded icon.
/// Returns a base64-encoded string that contains the resulting QR code as a PNG image.
/// </summary>
/// <param name="pixelsPerModule">The number of pixels each dark/light module of the QR code will occupy in the final QR code image.</param>
/// <param name="darkColor">The color of the dark modules.</param>
/// <param name="lightColor">The color of the light modules.</param>
/// <param name="icon">The icon to embed in the center of the QR code.</param>
/// <param name="iconSizePercent">The size of the icon as a percentage of the QR code.</param>
/// <param name="iconBorderWidth">The width of the border around the icon.</param>
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Bitmap icon, int iconSizePercent = 15, int iconBorderWidth = 6, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true)
{
var qr = new QRCode(QrCodeData);
var base64 = string.Empty;
using (var bmp = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, icon, iconSizePercent, iconBorderWidth, drawQuietZones))
{
base64 = BitmapToBase64(bmp, imgType);
}
return base64;
}

/// <summary>
/// Converts a bitmap to a base64-encoded string.
/// </summary>
/// <param name="bmp">The bitmap to convert.</param>
/// <param name="imgType">The type of image (PNG, JPEG, GIF).</param>
/// <returns>Returns the base64-encoded string representation of the bitmap.</returns>
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
private static string BitmapToBase64(Bitmap bmp, ImageType imgType)
{
var iFormat = imgType switch
{
ImageType.Png => ImageFormat.Png,
ImageType.Jpeg => ImageFormat.Jpeg,
ImageType.Gif => ImageFormat.Gif,
_ => ImageFormat.Png,
};
using var memoryStream = new MemoryStream();
bmp.Save(memoryStream, iFormat);
return Convert.ToBase64String(memoryStream.ToArray(), Base64FormattingOptions.None);
using var pngCoder = new PngByteQRCode(QrCodeData);
var pngData = pngCoder.GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones);
return Convert.ToBase64String(pngData, Base64FormattingOptions.None);
}

/// <summary>
/// Specifies the type of image to generate.
/// </summary>
[Obsolete("ImageType enum is obsolete. Only PNG format is supported.")]
public enum ImageType
{
/// <summary>
/// Graphics Interchange Format (GIF) image format, a bitmap image format with limited color support
/// </summary>
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
Gif,
/// <summary>
/// Joint Photographic Experts Group (JPEG) image format, a lossy compressed image format
/// </summary>
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
Jpeg,
/// <summary>
/// Portable Network Graphics (PNG) image format, a lossless raster graphics format
/// </summary>
Png
}

}

/// <summary>
/// Provides static methods for creating base64-encoded QR codes.
/// </summary>
public static class Base64QRCodeHelper
{
/// <summary>
/// Creates a base64-encoded QR code as a one-shot operation.
/// </summary>
/// <param name="plainText">The text or payload to be encoded inside the QR code.</param>
/// <param name="pixelsPerModule">The number of pixels each dark/light module of the QR code will occupy in the final QR code image.</param>
/// <param name="darkColorHtmlHex">The color of the dark modules in HTML hex format.</param>
/// <param name="lightColorHtmlHex">The color of the light modules in HTML hex format.</param>
/// <param name="eccLevel">The level of error correction data.</param>
/// <param name="forceUtf8">Specifies whether the generator should be forced to work in UTF-8 mode.</param>
/// <param name="utf8BOM">Specifies whether the byte-order-mark should be used.</param>
/// <param name="eciMode">Specifies which ECI mode should be used.</param>
/// <param name="requestedVersion">Sets the fixed QR code target version.</param>
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
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)
{
using var qrGenerator = new QRCodeGenerator();
using var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion);
using var qrCode = new Base64QRCode(qrCodeData);
return qrCode.GetGraphic(pixelsPerModule, darkColorHtmlHex, lightColorHtmlHex, drawQuietZones);
}

/// <summary>
/// Creates a base64-encoded QR code with a single function call.
/// </summary>
Expand All @@ -186,7 +156,8 @@ public static class Base64QRCodeHelper
/// <param name="drawQuietZones">Indicates if quiet zones around the QR code should be drawn.</param>
/// <param name="imgType">The type of image to generate (PNG, JPEG, GIF).</param>
/// <returns>Returns the QR code graphic as a base64-encoded string.</returns>
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)
[Obsolete("The imgType parameter is obsolete. Only PNG format is supported. Use the overload without the imgType parameter.")]
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)
{
using var qrGenerator = new QRCodeGenerator();
using var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion);
Expand Down
Loading