diff --git a/QRCoder/QRCoder.csproj b/QRCoder/QRCoder.csproj
index d67a7989..445e4aa8 100644
--- a/QRCoder/QRCoder.csproj
+++ b/QRCoder/QRCoder.csproj
@@ -1,63 +1,74 @@
-
- net35;net40;netstandard1.3;netstandard2.0;net5.0;net5.0-windows;net6.0;net6.0-windows
- false
- $(DefineConstants);NET5_0_WINDOWS
- $(DefineConstants);NET6_0_WINDOWS
- false
- true
-
-
-
-
-
-
-
- false
- QRCoder
- 1.4.3
- Raffael Herrmann
- Raffael Herrmann
- QRCoder
- MIT
- https://github.com/codebude/QRCoder/
- nuget-icon.png
- nuget-readme.md
- c# csharp qr qrcoder qrcode qr-generator qr-code-generator
- https://github.com/codebude/QRCoder.git
- git
- QRCoder is a simple library, written in C#.NET, which enables you to create QR codes.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ net35;net40;netstandard1.3;netstandard2.0;net5.0;net5.0-windows;net6.0;net6.0-windows
+ false
+ $(DefineConstants);NET5_0_WINDOWS
+ $(DefineConstants);NET6_0_WINDOWS
+ false
+ true
+
+
+
+
+
+
+
+ false
+ QRCoder
+ 1.4.3
+ Raffael Herrmann
+ Raffael Herrmann
+ QRCoder
+ MIT
+ https://github.com/codebude/QRCoder/
+ nuget-icon.png
+ nuget-readme.md
+ c# csharp qr qrcoder qrcode qr-generator qr-code-generator
+ https://github.com/codebude/QRCoder.git
+ git
+ QRCoder is a simple library, written in C#.NET, which enables you to create QR codes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.88.3
+
+
+
+
+ 2.88.3
+
-
- $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client
- false
- true
- QRCoderStrongName.snk
- false
-
+
+
+
+
+ $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client
+ false
+ true
+ QRCoderStrongName.snk
+ false
+
diff --git a/QRCoder/SvgQRCode_NET6.cs b/QRCoder/SvgQRCode_NET6.cs
new file mode 100644
index 00000000..a8a55325
--- /dev/null
+++ b/QRCoder/SvgQRCode_NET6.cs
@@ -0,0 +1,384 @@
+#if NET6_0
+using QRCoder.Extensions;
+using SkiaSharp;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using static QRCoder.QRCodeGenerator;
+using static QRCoder.SvgQRCode_NET6;
+
+namespace QRCoder
+{
+ ///
+ /// There class is basically the same as SvgQrCode but removed all System.Drawing
+ ///
+ public class SvgQRCode_NET6 : AbstractQRCode, IDisposable
+ {
+ ///
+ /// Constructor without params to be used in COM Objects connections
+ ///
+ public SvgQRCode_NET6() { }
+ public SvgQRCode_NET6(QRCodeData data) : base(data) { }
+ public string GetGraphic(int pixelsPerModule)
+ {
+ var viewBox = new SKSize(pixelsPerModule * this.QrCodeData.ModuleMatrix.Count, pixelsPerModule * this.QrCodeData.ModuleMatrix.Count);
+ return this.GetGraphic(viewBox, SKColors.Black, SKColors.White);
+ }
+
+ ///
+ /// Returns a QR code as SVG string with custom colors, optional quietzone and logo
+ ///
+ /// The pixel size each b/w module is drawn
+ /// Color of the dark modules
+ /// Color of the light modules
+ /// If true a white border is drawn around the whole QR Code
+ /// Defines if width/height or viewbox should be used for size definition
+ /// A (optional) logo to be rendered on the code (either Bitmap or SVG)
+ /// SVG as string
+ public string GetGraphic(int pixelsPerModule, SKColor darkColor, SKColor lightColor, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo_NET6 logo = null)
+ {
+ var offset = drawQuietZones ? 0 : 4;
+ var edgeSize = this.QrCodeData.ModuleMatrix.Count * pixelsPerModule - (offset * 2 * pixelsPerModule);
+ var viewBox = new SKSize(edgeSize, edgeSize);
+ return this.GetGraphic(viewBox, darkColor.ToString(), lightColor.ToString(), drawQuietZones, sizingMode, logo);
+ }
+
+ ///
+ /// Returns a QR code as SVG string with custom colors (in HEX syntax), optional quietzone and logo
+ ///
+ /// The pixel size each b/w module is drawn
+ /// The color of the dark/black modules in hex (e.g. #000000) representation
+ /// The color of the light/white modules in hex (e.g. #ffffff) representation
+ /// If true a white border is drawn around the whole QR Code
+ /// Defines if width/height or viewbox should be used for size definition
+ /// A (optional) logo to be rendered on the code (either Bitmap or SVG)
+ /// SVG as string
+ public string GetGraphic(int pixelsPerModule, string darkColorHex, string lightColorHex, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo_NET6 logo = null)
+ {
+ var offset = drawQuietZones ? 0 : 4;
+ var edgeSize = this.QrCodeData.ModuleMatrix.Count * pixelsPerModule - (offset * 2 * pixelsPerModule);
+ var viewBox = new SKSize(edgeSize, edgeSize);
+ return this.GetGraphic(viewBox, darkColorHex, lightColorHex, drawQuietZones, sizingMode, logo);
+ }
+
+ ///
+ /// Returns a QR code as SVG string with custom colors (in HEX syntax), optional quietzone and logo
+ ///
+ /// The viewbox of the QR code graphic
+ /// The color of the dark/black modules in hex (e.g. #000000) representation
+ /// The color of the light/white modules in hex (e.g. #ffffff) representation
+ /// If true a white border is drawn around the whole QR Code
+ /// Defines if width/height or viewbox should be used for size definition
+ /// A (optional) logo to be rendered on the code (either Bitmap or SVG)
+ /// SVG as string
+ public string GetGraphic(SKSize viewBox, string darkColorHex, string lightColorHex, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo_NET6 logo = null)
+ {
+ int offset = drawQuietZones ? 0 : 4;
+ int drawableModulesCount = this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : offset * 2);
+ double pixelsPerModule = Math.Min(viewBox.Width, viewBox.Height) / (double)drawableModulesCount;
+ double qrSize = drawableModulesCount * pixelsPerModule;
+ string svgSizeAttributes = (sizingMode == SizingMode.WidthHeightAttribute) ? $@"width=""{viewBox.Width}"" height=""{viewBox.Height}""" : $@"viewBox=""0 0 {viewBox.Width} {viewBox.Height}""";
+ ImageAttributes? logoAttr = null;
+ if (logo != null)
+ logoAttr = GetLogoAttributes(logo, viewBox);
+
+ // Merge horizontal rectangles
+ int[,] matrix = new int[drawableModulesCount, drawableModulesCount];
+ for (int yi = 0; yi < drawableModulesCount; yi += 1)
+ {
+ BitArray bitArray = this.QrCodeData.ModuleMatrix[yi + offset];
+
+ int x0 = -1;
+ int xL = 0;
+ for (int xi = 0; xi < drawableModulesCount; xi += 1)
+ {
+ matrix[yi, xi] = 0;
+ if (bitArray[xi + offset] && (logo == null || !logo.FillLogoBackground() || !IsBlockedByLogo((xi + offset) * pixelsPerModule, (yi + offset) * pixelsPerModule, logoAttr, pixelsPerModule)))
+ {
+ if (x0 == -1)
+ {
+ x0 = xi;
+ }
+ xL += 1;
+ }
+ else
+ {
+ if (xL > 0)
+ {
+ matrix[yi, x0] = xL;
+ x0 = -1;
+ xL = 0;
+ }
+ }
+ }
+
+ if (xL > 0)
+ {
+ matrix[yi, x0] = xL;
+ }
+ }
+
+ StringBuilder svgFile = new StringBuilder($@"");
+ return svgFile.ToString();
+ }
+
+ ///
+ /// Returns a QR code as SVG string with optional quietzone and logo
+ ///
+ /// The viewbox of the QR code graphic
+ /// If true a white border is drawn around the whole QR Code
+ /// Defines if width/height or viewbox should be used for size definition
+ /// A (optional) logo to be rendered on the code (either Bitmap or SVG)
+ /// SVG as string
+ public string GetGraphic(SKSize viewBox, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo_NET6 logo = null)
+ {
+ return this.GetGraphic(viewBox, SKColors.Black, SKColors.White, drawQuietZones, sizingMode, logo);
+ }
+
+ ///
+ /// Returns a QR code as SVG string with custom colors and optional quietzone and logo
+ ///
+ /// The viewbox of the QR code graphic
+ /// Color of the dark modules
+ /// Color of the light modules
+ /// If true a white border is drawn around the whole QR Code
+ /// Defines if width/height or viewbox should be used for size definition
+ /// A (optional) logo to be rendered on the code (either Bitmap or SVG)
+ /// SVG as string
+ public string GetGraphic(SKSize viewBox, SKColor darkColor, SKColor lightColor, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo_NET6 logo = null)
+ {
+ return this.GetGraphic(viewBox, darkColor.ToString(), lightColor.ToString(), drawQuietZones, sizingMode, logo);
+ }
+
+ private bool IsBlockedByLogo(double x, double y, ImageAttributes? attr, double pixelPerModule)
+ {
+ return x + pixelPerModule >= attr.Value.X && x <= attr.Value.X + attr.Value.Width && y + pixelPerModule >= attr.Value.Y && y <= attr.Value.Y + attr.Value.Height;
+ }
+
+ private ImageAttributes GetLogoAttributes(SvgLogo_NET6 logo, SKSize viewBox)
+ {
+ var imgWidth = logo.GetIconSizePercent() / 100d * viewBox.Width;
+ var imgHeight = logo.GetIconSizePercent() / 100d * viewBox.Height;
+ var imgPosX = viewBox.Width / 2d - imgWidth / 2d;
+ var imgPosY = viewBox.Height / 2d - imgHeight / 2d;
+ return new ImageAttributes()
+ {
+ Width = imgWidth,
+ Height = imgHeight,
+ X = imgPosX,
+ Y = imgPosY
+ };
+ }
+
+ private struct ImageAttributes
+ {
+ public double Width;
+ public double Height;
+ public double X;
+ public double Y;
+ }
+
+ private string CleanSvgVal(double input)
+ {
+ //Clean double values for international use/formats
+ //We use explicitly "G15" to avoid differences between .NET full and Core platforms
+ //https://stackoverflow.com/questions/64898117/tostring-has-a-different-behavior-between-net-462-and-net-core-3-1
+ return input.ToString("G15", System.Globalization.CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Mode of sizing attribution on svg root node
+ ///
+ public enum SizingMode
+ {
+ WidthHeightAttribute,
+ ViewBoxAttribute
+ }
+
+ ///
+ /// Represents a logo graphic that can be rendered on a SvgQRCode_NET6
+ ///
+ public class SvgLogo_NET6
+ {
+ private string _logoData;
+ private MediaType _mediaType;
+ private int _iconSizePercent;
+ private bool _fillLogoBackground;
+ private object _logoRaw;
+ private bool _isEmbedded;
+
+
+ ///
+ /// Create a logo object to be used in SvgQRCode_NET6 renderer
+ ///
+ /// Logo to be rendered as Bitmap/rasterized graphic
+ /// Degree of percentage coverage of the QR code by the logo
+ /// If true, the background behind the logo will be cleaned
+ public SvgLogo_NET6(SKImage iconRasterized, int iconSizePercent = 15, bool fillLogoBackground = true)
+ {
+ _iconSizePercent = iconSizePercent;
+ using (var ms = new System.IO.MemoryStream())
+ {
+ iconRasterized.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
+ _logoData = Convert.ToBase64String(ms.GetBuffer(), Base64FormattingOptions.None);
+ }
+
+ _mediaType = MediaType.PNG;
+ _fillLogoBackground = fillLogoBackground;
+ _logoRaw = iconRasterized;
+ _isEmbedded = false;
+ }
+
+ ///
+ /// Create a logo object to be used in SvgQRCode_NET6 renderer
+ ///
+ /// Logo to be rendered as SVG/vectorized graphic/string
+ /// Degree of percentage coverage of the QR code by the logo
+ /// If true, the background behind the logo will be cleaned
+ /// If true, the logo will embedded as native svg instead of embedding it as image-tag
+ public SvgLogo_NET6(string iconVectorized, int iconSizePercent = 15, bool fillLogoBackground = true, bool iconEmbedded = true)
+ {
+ _iconSizePercent = iconSizePercent;
+ _logoData = Convert.ToBase64String(Encoding.UTF8.GetBytes(iconVectorized), Base64FormattingOptions.None);
+ _mediaType = MediaType.SVG;
+ _fillLogoBackground = fillLogoBackground;
+ _logoRaw = iconVectorized;
+ _isEmbedded = iconEmbedded;
+ }
+
+ ///
+ /// Returns the raw logo's data
+ ///
+ ///
+ public object GetRawLogo()
+ {
+ return _logoRaw;
+ }
+
+ ///
+ /// Defines, if the logo shall be natively embedded.
+ /// true=native svg embedding, false=embedding via image-tag
+ ///
+ ///
+ public bool IsEmbedded()
+ {
+ return _isEmbedded;
+ }
+
+ ///
+ /// Returns the media type of the logo
+ ///
+ ///
+ public MediaType GetMediaType()
+ {
+ return _mediaType;
+ }
+
+ ///
+ /// Returns the logo as data-uri
+ ///
+ ///
+ public string GetDataUri()
+ {
+ return $"data:{_mediaType.GetStringValue()};base64,{_logoData}";
+ }
+
+ ///
+ /// Returns how much of the QR code should be covered by the logo (in percent)
+ ///
+ ///
+ public int GetIconSizePercent()
+ {
+ return _iconSizePercent;
+ }
+
+ ///
+ /// Returns if the background of the logo should be cleaned (no QR modules will be rendered behind the logo)
+ ///
+ ///
+ public bool FillLogoBackground()
+ {
+ return _fillLogoBackground;
+ }
+
+ ///
+ /// Media types for SvgLogo_NET6s
+ ///
+ public enum MediaType : int
+ {
+ [StringValue("image/png")]
+ PNG = 0,
+ [StringValue("image/svg+xml")]
+ SVG = 1
+ }
+ }
+ }
+ public static class SvgQRCode_NET6Helper
+ {
+ public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorHex, string lightColorHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo_NET6 logo = null)
+ {
+ using (var qrGenerator = new QRCodeGenerator())
+ using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
+ using (var qrCode = new SvgQRCode_NET6(qrCodeData))
+ return qrCode.GetGraphic(pixelsPerModule, darkColorHex, lightColorHex, drawQuietZones, sizingMode, logo);
+ }
+ }
+}
+#endif
\ No newline at end of file