Skip to content

Commit 2fb0819

Browse files
committed
Add ImageSharp renderers for .net 6.0, 5.0 and standart 2.0
1 parent dd35a3b commit 2fb0819

File tree

8 files changed

+302
-16
lines changed

8 files changed

+302
-16
lines changed

QRCoder/Base64QRCode.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Drawing;
44
using System.Drawing.Imaging;
55
using System.IO;
6-
using static QRCoder.Base64QRCode;
76
using static QRCoder.QRCodeGenerator;
87

98
namespace QRCoder
@@ -88,13 +87,6 @@ private string BitmapToBase64(Bitmap bmp, ImageType imgType)
8887
return base64;
8988
}
9089

91-
public enum ImageType
92-
{
93-
Gif,
94-
Jpeg,
95-
Png
96-
}
97-
9890
}
9991

10092
#if NET6_0_WINDOWS

QRCoder/ImageSharp/Base64QRCode.cs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using System;
2+
using System.IO;
3+
using SixLabors.ImageSharp;
4+
using SixLabors.ImageSharp.Formats;
5+
using static QRCoder.QRCodeGenerator;
6+
7+
namespace QRCoder.ImageSharp
8+
{
9+
public class Base64QRCode : AbstractQRCode, IDisposable
10+
{
11+
private QRCode qr;
12+
13+
/// <summary>
14+
/// Constructor without params to be used in COM Objects connections
15+
/// </summary>
16+
public Base64QRCode()
17+
{
18+
qr = new QRCode();
19+
}
20+
21+
public Base64QRCode(QRCodeData data)
22+
: base(data)
23+
{
24+
qr = new QRCode(data);
25+
}
26+
27+
public override void SetQRCodeData(QRCodeData data)
28+
{
29+
qr.SetQRCodeData(data);
30+
}
31+
32+
public string GetGraphic(int pixelsPerModule)
33+
{
34+
return GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
35+
}
36+
37+
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
38+
{
39+
return GetGraphic(pixelsPerModule, Color.Parse(darkColorHtmlHex), Color.Parse(lightColorHtmlHex), drawQuietZones, imgType);
40+
}
41+
42+
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
43+
{
44+
var base64 = string.Empty;
45+
using (Image img = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones))
46+
{
47+
base64 = BitmapToBase64(img, imgType);
48+
}
49+
50+
return base64;
51+
}
52+
53+
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Image icon, int iconSizePercent = 15, int iconBorderWidth = 6, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
54+
{
55+
var base64 = string.Empty;
56+
using (Image bmp = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, icon, iconSizePercent, iconBorderWidth, drawQuietZones))
57+
{
58+
base64 = BitmapToBase64(bmp, imgType);
59+
}
60+
61+
return base64;
62+
}
63+
64+
private string BitmapToBase64(Image img, ImageType imgType)
65+
{
66+
var base64 = string.Empty;
67+
IImageEncoder iFormat;
68+
switch (imgType)
69+
{
70+
default:
71+
case ImageType.Png:
72+
iFormat = new SixLabors.ImageSharp.Formats.Png.PngEncoder();
73+
break;
74+
case ImageType.Jpeg:
75+
iFormat = new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder();
76+
break;
77+
case ImageType.Gif:
78+
iFormat = new SixLabors.ImageSharp.Formats.Gif.GifEncoder();
79+
break;
80+
}
81+
82+
using (var memoryStream = new MemoryStream())
83+
{
84+
img.Save(memoryStream, iFormat);
85+
base64 = Convert.ToBase64String(memoryStream.ToArray(), Base64FormattingOptions.None);
86+
}
87+
88+
return base64;
89+
}
90+
}
91+
92+
public static class ImageSharpBase64QRCodeHelper
93+
{
94+
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)
95+
{
96+
using (var qrGenerator = new QRCodeGenerator())
97+
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
98+
using (var qrCode = new Base64QRCode(qrCodeData))
99+
{
100+
return qrCode.GetGraphic(pixelsPerModule, darkColorHtmlHex, lightColorHtmlHex, drawQuietZones, imgType);
101+
}
102+
}
103+
}
104+
}

QRCoder/ImageSharp/QRCode.cs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using System;
2+
using SixLabors.ImageSharp;
3+
using SixLabors.ImageSharp.PixelFormats;
4+
using SixLabors.ImageSharp.Processing;
5+
using static QRCoder.QRCodeGenerator;
6+
7+
namespace QRCoder.ImageSharp
8+
{
9+
public class QRCode : AbstractQRCode, IDisposable
10+
{
11+
/// <summary>
12+
/// Constructor without params to be used in COM Objects connections
13+
/// </summary>
14+
public QRCode() { }
15+
16+
public QRCode(QRCodeData data)
17+
: base(data) { }
18+
19+
public Image GetGraphic(int pixelsPerModule)
20+
{
21+
return GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
22+
}
23+
24+
public Image GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true)
25+
{
26+
return GetGraphic(pixelsPerModule, Color.Parse(darkColorHtmlHex), Color.Parse(lightColorHtmlHex), drawQuietZones);
27+
}
28+
29+
public Image GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true)
30+
{
31+
var moduleOffset = drawQuietZones ? 0 : 4;
32+
var size = (QrCodeData.ModuleMatrix.Count - (moduleOffset * 2)) * pixelsPerModule;
33+
34+
var image = new Image<Rgba32>(size, size);
35+
DrawQRCode(image, pixelsPerModule, moduleOffset, darkColor, lightColor);
36+
37+
return image;
38+
}
39+
40+
public Image GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Image icon = null, int iconSizePercent = 15, int iconBorderWidth = 0, bool drawQuietZones = true, Color? iconBackgroundColor = null)
41+
{
42+
var img = GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones) as Image<Rgba32>;
43+
if (icon != null && iconSizePercent > 0 && iconSizePercent <= 100)
44+
{
45+
var iconDestWidth = iconSizePercent * img.Width / 100f;
46+
var iconDestHeight = iconDestWidth * icon.Height / icon.Width;
47+
var iconX = (img.Width - iconDestWidth) / 2;
48+
var iconY = (img.Height - iconDestHeight) / 2;
49+
var centerDest = new RectangleF(iconX - iconBorderWidth, iconY - iconBorderWidth, iconDestWidth + (iconBorderWidth * 2), iconDestHeight + (iconBorderWidth * 2));
50+
var iconDestRect = new RectangleF(iconX, iconY, iconDestWidth, iconDestHeight);
51+
52+
if (iconBorderWidth > 0)
53+
{
54+
if (!iconBackgroundColor.HasValue)
55+
{
56+
iconBackgroundColor = lightColor;
57+
}
58+
59+
if (iconBackgroundColor != Color.Transparent)
60+
{
61+
img.ProcessPixelRows(accessor =>
62+
{
63+
for (var y = (int)centerDest.Top; y <= (int)centerDest.Bottom; y++)
64+
{
65+
var pixelRow = accessor.GetRowSpan(y);
66+
67+
for (var x = (int)centerDest.Left; x <= (int)centerDest.Right; x++)
68+
{
69+
pixelRow[x] = iconBackgroundColor ?? lightColor;
70+
}
71+
}
72+
});
73+
}
74+
}
75+
76+
var sizedIcon = icon.Clone(x => x.Resize((int)iconDestWidth, (int)iconDestHeight));
77+
img.Mutate(x => x.DrawImage(sizedIcon, new Point((int)iconDestRect.X, (int)iconDestRect.Y), 1));
78+
}
79+
80+
return img;
81+
}
82+
83+
private void DrawQRCode(Image<Rgba32> image, int pixelsPerModule, int moduleOffset, Color darkColor, Color lightColor)
84+
{
85+
var row = new Rgba32[image.Width];
86+
87+
image.ProcessPixelRows(accessor =>
88+
{
89+
for (var modY = moduleOffset; modY < QrCodeData.ModuleMatrix.Count - moduleOffset; modY++)
90+
{
91+
// Generate row for this y-Module
92+
for (var modX = moduleOffset; modX < QrCodeData.ModuleMatrix.Count - moduleOffset; modX++)
93+
{
94+
for (var idx = 0; idx < pixelsPerModule; idx++)
95+
{
96+
row[((modX - moduleOffset) * pixelsPerModule) + idx] = this.QrCodeData.ModuleMatrix[modY][modX] ? darkColor : lightColor;
97+
}
98+
}
99+
100+
// Copy the prepared row to the image
101+
for (var idx = 0; idx < pixelsPerModule; idx++)
102+
{
103+
var pixelRow = accessor.GetRowSpan(((modY - moduleOffset) * pixelsPerModule) + idx);
104+
row.CopyTo(pixelRow);
105+
}
106+
}
107+
});
108+
}
109+
}
110+
111+
public static class ImageSharpQRCodeHelper
112+
{
113+
public static Image GetQRCode(string plainText, int pixelsPerModule, Color darkColor, Color lightColor, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, Image icon = null, int iconSizePercent = 15, int iconBorderWidth = 0, bool drawQuietZones = true)
114+
{
115+
using (var qrGenerator = new QRCodeGenerator())
116+
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
117+
using (var qrCode = new QRCode(qrCodeData))
118+
{
119+
return qrCode.GetGraphic(pixelsPerModule,
120+
darkColor,
121+
lightColor,
122+
icon,
123+
iconSizePercent,
124+
iconBorderWidth,
125+
drawQuietZones);
126+
}
127+
}
128+
}
129+
}

QRCoder/ImageType.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace QRCoder
2+
{
3+
public enum ImageType
4+
{
5+
Gif,
6+
Jpeg,
7+
Png
8+
}
9+
}

QRCoder/QRCoder.csproj

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>net35;net40;netstandard1.3;netstandard2.0;net5.0;net5.0-windows;net6.0;net6.0-windows</TargetFrameworks>
55
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
66
<DefineConstants Condition="'$(TargetFramework)' == 'net5.0-windows'">$(DefineConstants);NET5_0_WINDOWS</DefineConstants>
7-
<DefineConstants Condition="'$(TargetFramework)' == 'net6.0-windows'">$(DefineConstants);NET6_0_WINDOWS</DefineConstants>
7+
<DefineConstants Condition="'$(TargetFramework)' == 'net6.0-windows'">$(DefineConstants);NET6_0_WINDOWS</DefineConstants>
88
<CheckEolTargetFramework>false</CheckEolTargetFramework>
99
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
1010
</PropertyGroup>
@@ -48,9 +48,17 @@
4848
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'net5.0' or '$(TargetFramework)' == 'net5.0-windows' ">
4949
<PackageReference Include="System.Drawing.Common" Version="5.0.3" />
5050
</ItemGroup>
51-
<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0-windows' ">
52-
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
53-
</ItemGroup>
51+
<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0-windows' ">
52+
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
53+
</ItemGroup>
54+
<ItemGroup Condition=" $(TargetFramework.StartsWith('net5.0')) == true or $(TargetFramework.StartsWith('net6.0')) == true or '$(TargetFramework)' == 'netstandard2.0' ">
55+
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.4" />
56+
</ItemGroup>
57+
58+
<ItemGroup Condition=" $(TargetFramework.StartsWith('net5.0')) != true and $(TargetFramework.StartsWith('net6.0')) != true and '$(TargetFramework)' != 'netstandard2.0' ">
59+
<None Include="ImageSharp\*" />
60+
<Compile Remove="ImageSharp\*" />
61+
</ItemGroup>
5462

5563
<PropertyGroup>
5664
<FrameworkPathOverride Condition="'$(TargetFramework)' == 'net35'">$(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client</FrameworkPathOverride>

QRCoderConsole/Program.cs

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
using System;
2+
#if !IMAGE_SHARP
23
using System.Drawing.Imaging;
4+
#else
5+
using SixLabors.ImageSharp;
6+
using SixLabors.ImageSharp.Formats;
7+
using SixLabors.ImageSharp.Formats.Jpeg;
8+
using SixLabors.ImageSharp.Formats.Png;
9+
using SixLabors.ImageSharp.Formats.Gif;
10+
using SixLabors.ImageSharp.Formats.Bmp;
11+
using SixLabors.ImageSharp.Formats.Tiff;
12+
#endif
313
using System.IO;
414
using NDesk.Options;
515
using QRCoderConsole.DataObjects;
@@ -147,6 +157,7 @@ private static void GenerateQRCode(string payloadString, QRCodeGenerator.ECCLeve
147157
case SupportedImageFormat.Gif:
148158
case SupportedImageFormat.Bmp:
149159
case SupportedImageFormat.Tiff:
160+
#if !IMAGE_SHARP
150161
using (var code = new QRCode(data))
151162
{
152163
using (var bitmap = code.GetGraphic(pixelsPerModule, foreground, background, true))
@@ -155,6 +166,17 @@ private static void GenerateQRCode(string payloadString, QRCodeGenerator.ECCLeve
155166
bitmap.Save(outputFileName, actualFormat);
156167
}
157168
}
169+
#else
170+
using (var code = new QRCoder.ImageSharp.QRCode(data))
171+
{
172+
using (var bitmap = code.GetGraphic(pixelsPerModule, foreground, background, true))
173+
{
174+
var actualFormat = new OptionSetter().GetImageFormat(imgFormat.ToString());
175+
bitmap.Save(outputFileName, actualFormat);
176+
}
177+
}
178+
#endif
179+
158180
break;
159181
case SupportedImageFormat.Svg:
160182
using (var code = new SvgQRCode(data))
@@ -251,9 +273,7 @@ public QRCodeGenerator.ECCLevel GetECCLevel(string value)
251273
return level;
252274
}
253275

254-
#if NET6_0_WINDOWS
255-
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
256-
#endif
276+
#if !IMAGE_SHARP
257277
public ImageFormat GetImageFormat(string value)
258278
{
259279
switch (value.ToLower())
@@ -273,6 +293,27 @@ public ImageFormat GetImageFormat(string value)
273293
return ImageFormat.Png;
274294
}
275295
}
296+
#else
297+
public IImageEncoder GetImageFormat(string value)
298+
{
299+
switch (value.ToLower())
300+
{
301+
case "jpg":
302+
return new JpegEncoder();
303+
case "jpeg":
304+
return new PngEncoder();
305+
case "gif":
306+
return new GifEncoder();
307+
case "bmp":
308+
return new BmpEncoder();
309+
case "tiff":
310+
return new TiffEncoder();
311+
case "png":
312+
default:
313+
return new PngEncoder();
314+
}
315+
}
316+
#endif
276317
}
277318
}
278319

QRCoderConsole/QRCoderConsole.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
<!-- <UseWindowsForms Condition="'$(TargetFramework)' == 'net5.0-windows' or '$(TargetFramework)' == 'net5.0-windows'">true</UseWindowsForms>-->
66
<UseWPF Condition="'$(TargetFramework)' == 'net5.0-windows' or '$(TargetFramework)' == 'net6.0-windows'">true</UseWPF>
77
<DefineConstants Condition="'$(TargetFramework)' == 'net5.0-windows'">$(DefineConstants);NET5_0_WINDOWS</DefineConstants>
8-
<DefineConstants Condition="'$(TargetFramework)' == 'net6.0-windows'">$(DefineConstants);NET6_0_WINDOWS</DefineConstants>
8+
<DefineConstants Condition="'$(TargetFramework)' == 'net6.0-windows'">$(DefineConstants);NET6_0_WINDOWS</DefineConstants>
9+
<DefineConstants Condition=" $(TargetFramework.StartsWith('net5.0')) == true or $(TargetFramework.StartsWith('net6.0')) == true or '$(TargetFramework)' == 'netstandard2.0' ">$(DefineConstants);IMAGE_SHARP</DefineConstants>
910
<Externalconsole>true</Externalconsole>
1011
<OutputType>Exe</OutputType>
1112
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ Besides the normal QRCode class (which is shown in the example above) for creati
8484
* [SvgQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#26-svgqrcode-renderer-in-detail)
8585
* [UnityQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#27-unityqrcode-renderer-in-detail) (_via [QRCoder.Unity](https://www.nuget.org/packages/QRCoder.Unity)_)
8686
* [XamlQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#28-xamlqrcode-renderer-in-detail) (_via [QRCoder.Xaml](https://www.nuget.org/packages/QRCoder.Xaml)_)
87+
* ImageSharp.QRCode (repeats logic of QRCode but uses ImageSharp under the hood)
88+
* ImageSharp.Base64QRCode (repeats logic of Base64QRCode but uses ImageSharp under the hood)
8789

8890
*Note: Please be aware that not all renderers are available on all target frameworks. Please check the [compatibility table](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#2-overview-of-the-different-renderers) in our wiki, to see if a specific renderer is available on your favourite target framework.*
8991

0 commit comments

Comments
 (0)