diff --git a/QRCoder/Builders/Payloads/IConfigurableEccLevel.cs b/QRCoder/Builders/Payloads/IConfigurableEccLevel.cs new file mode 100644 index 00000000..422318ad --- /dev/null +++ b/QRCoder/Builders/Payloads/IConfigurableEccLevel.cs @@ -0,0 +1,7 @@ +namespace QRCoder.Builders.Payloads +{ + public interface IConfigurableEccLevel + { + QRCodeGenerator.ECCLevel EccLevel { get; set; } + } +} diff --git a/QRCoder/Builders/Payloads/IConfigurableEciMode.cs b/QRCoder/Builders/Payloads/IConfigurableEciMode.cs new file mode 100644 index 00000000..4f2c30a5 --- /dev/null +++ b/QRCoder/Builders/Payloads/IConfigurableEciMode.cs @@ -0,0 +1,7 @@ +namespace QRCoder.Builders.Payloads +{ + public interface IConfigurableEciMode + { + QRCodeGenerator.EciMode EciMode { get; set; } + } +} diff --git a/QRCoder/Builders/Payloads/IConfigurableVersion.cs b/QRCoder/Builders/Payloads/IConfigurableVersion.cs new file mode 100644 index 00000000..dfe9eb02 --- /dev/null +++ b/QRCoder/Builders/Payloads/IConfigurableVersion.cs @@ -0,0 +1,7 @@ +namespace QRCoder.Builders.Payloads +{ + public interface IConfigurableVersion + { + int Version { get; set; } + } +} diff --git a/QRCoder/Builders/Payloads/IPayload.cs b/QRCoder/Builders/Payloads/IPayload.cs new file mode 100644 index 00000000..4096f592 --- /dev/null +++ b/QRCoder/Builders/Payloads/IPayload.cs @@ -0,0 +1,7 @@ +namespace QRCoder.Builders.Payloads +{ + public interface IPayload + { + QRCodeData ToMatrix(); + } +} diff --git a/QRCoder/Builders/Payloads/Implementations/EmailPayload.cs b/QRCoder/Builders/Payloads/Implementations/EmailPayload.cs new file mode 100644 index 00000000..e94b2ca9 --- /dev/null +++ b/QRCoder/Builders/Payloads/Implementations/EmailPayload.cs @@ -0,0 +1,41 @@ +using System; + +namespace QRCoder.Builders.Payloads.Implementations +{ + public class EmailPayload : PayloadBase + { + public EmailPayload(string address) + { + _address = address; + } + + private string _address { get; set; } + private string _subject { get; set; } + private string _body { get; set; } + private PayloadGenerator.Mail.MailEncoding _encoding { get; set; } = PayloadGenerator.Mail.MailEncoding.MAILTO; + + public EmailPayload WithSubject(string subject) + { + _subject = subject; + return this; + } + + public EmailPayload WithBody(string body) + { + _body = body; + return this; + } + + public EmailPayload WithEncoding(PayloadGenerator.Mail.MailEncoding encoding) + { + if (encoding != PayloadGenerator.Mail.MailEncoding.MAILTO && encoding != PayloadGenerator.Mail.MailEncoding.SMTP && encoding != PayloadGenerator.Mail.MailEncoding.MATMSG) + { + throw new ArgumentOutOfRangeException(nameof(encoding)); + } + _encoding = encoding; + return this; + } + + protected override string Value => new PayloadGenerator.Mail(_address, _subject, _body, _encoding).ToString(); + } +} diff --git a/QRCoder/Builders/Payloads/Implementations/StringPayload.cs b/QRCoder/Builders/Payloads/Implementations/StringPayload.cs new file mode 100644 index 00000000..e1910dff --- /dev/null +++ b/QRCoder/Builders/Payloads/Implementations/StringPayload.cs @@ -0,0 +1,14 @@ +namespace QRCoder.Builders.Payloads.Implementations +{ + public class StringPayload : PayloadBase + { + private string _data; + + public StringPayload(string data) + { + _data = data; + } + + protected override string Value => _data; + } +} diff --git a/QRCoder/Builders/Payloads/Implementations/WiFiPayload.cs b/QRCoder/Builders/Payloads/Implementations/WiFiPayload.cs new file mode 100644 index 00000000..16ecdedd --- /dev/null +++ b/QRCoder/Builders/Payloads/Implementations/WiFiPayload.cs @@ -0,0 +1,46 @@ +namespace QRCoder.Builders.Payloads.Implementations +{ + public class WiFiPayload : PayloadBase + { + private string _ssid { get; set; } + private string _password { get; set; } + private PayloadGenerator.WiFi.Authentication _authentication { get; set; } + private bool _isHiddenSSID { get; set; } + private bool _isHexStrings { get; set; } + + public WiFiPayload(string ssid) + { + _ssid = ssid; + _password = ""; + _authentication = PayloadGenerator.WiFi.Authentication.nopass; + } + + public WiFiPayload(string ssid, string password, PayloadGenerator.WiFi.Authentication authentication) + { + _ssid = ssid; + _password = password; + _authentication = authentication; + } + + public WiFiPayload WithHiddenSSID() + { + _isHiddenSSID = true; + return this; + } + + public WiFiPayload WithHexStrings() + { + _isHexStrings = true; + return this; + } + + protected override string Value + { + get + { + var wifi = new PayloadGenerator.WiFi(_ssid, _password, _authentication, _isHiddenSSID, _isHexStrings); + return wifi.ToString(); + } + } + } +} diff --git a/QRCoder/Builders/Payloads/PayloadBase.cs b/QRCoder/Builders/Payloads/PayloadBase.cs new file mode 100644 index 00000000..e29cabec --- /dev/null +++ b/QRCoder/Builders/Payloads/PayloadBase.cs @@ -0,0 +1,21 @@ +namespace QRCoder.Builders.Payloads +{ + public abstract class PayloadBase : IPayload, IConfigurableEccLevel, IConfigurableEciMode, IConfigurableVersion + { + protected virtual QRCodeGenerator.ECCLevel EccLevel { get; set; } = QRCodeGenerator.ECCLevel.Default; + QRCodeGenerator.ECCLevel IConfigurableEccLevel.EccLevel { get => EccLevel; set => EccLevel = value; } + + protected virtual QRCodeGenerator.EciMode EciMode { get; set; } = QRCodeGenerator.EciMode.Default; + QRCodeGenerator.EciMode IConfigurableEciMode.EciMode { get => EciMode; set => EciMode = value; } + + protected virtual int Version { get; set; } = -1; + int IConfigurableVersion.Version { get => Version; set => Version = value; } + + protected abstract string Value { get; } + + public virtual QRCodeData ToMatrix() + { + return QRCodeGenerator.GenerateQrCode(Value, EccLevel, false, false, EciMode, Version); + } + } +} diff --git a/QRCoder/Builders/Payloads/PayloadExtensions.cs b/QRCoder/Builders/Payloads/PayloadExtensions.cs new file mode 100644 index 00000000..6f849302 --- /dev/null +++ b/QRCoder/Builders/Payloads/PayloadExtensions.cs @@ -0,0 +1,47 @@ +using QRCoder.Builders.Payloads; +using QRCoder.Builders.Renderers; +using QRCoder.Builders.Renderers.Implementations; + +namespace QRCoder +{ + public static class PayloadExtensions + { + public static T WithErrorCorrection(this T payload, QRCodeGenerator.ECCLevel eccLevel) + where T : IConfigurableEccLevel + { + payload.EccLevel = eccLevel; + return payload; + } + + public static T WithEciMode(this T payload, QRCodeGenerator.EciMode eciMode) + where T : IConfigurableEciMode + { + payload.EciMode = eciMode; + return payload; + } + + public static T WithVersion(this T payload, int version) + where T : IConfigurableVersion + { + payload.Version = version; + return payload; + } + + public static T RenderWith(this IPayload payload) + where T : IRenderer, new() + { + var renderer = new T(); + renderer.Payload = payload; + return renderer; + } + + public static T RenderWith(this IPayload payload, int pixelsPerModule) + where T : IRenderer, IConfigurablePixelsPerModule, new() + { + var renderer = new T(); + renderer.Payload = payload; + renderer.PixelsPerModule = pixelsPerModule; + return renderer; + } + } +} diff --git a/QRCoder/Builders/Renderers/IConfigurablePixelsPerModule.cs b/QRCoder/Builders/Renderers/IConfigurablePixelsPerModule.cs new file mode 100644 index 00000000..5893f814 --- /dev/null +++ b/QRCoder/Builders/Renderers/IConfigurablePixelsPerModule.cs @@ -0,0 +1,7 @@ +namespace QRCoder.Builders.Renderers +{ + public interface IConfigurablePixelsPerModule + { + int PixelsPerModule { get; set; } + } +} diff --git a/QRCoder/Builders/Renderers/IConfigurableQuietZones.cs b/QRCoder/Builders/Renderers/IConfigurableQuietZones.cs new file mode 100644 index 00000000..7c6be637 --- /dev/null +++ b/QRCoder/Builders/Renderers/IConfigurableQuietZones.cs @@ -0,0 +1,7 @@ +namespace QRCoder.Builders.Renderers +{ + public interface IConfigurableQuietZones + { + bool QuietZone { get; set; } + } +} diff --git a/QRCoder/Builders/Renderers/IRenderer.cs b/QRCoder/Builders/Renderers/IRenderer.cs new file mode 100644 index 00000000..ef20ac23 --- /dev/null +++ b/QRCoder/Builders/Renderers/IRenderer.cs @@ -0,0 +1,9 @@ +using QRCoder.Builders.Payloads; + +namespace QRCoder.Builders.Renderers +{ + public interface IRenderer + { + IPayload Payload { set; } + } +} diff --git a/QRCoder/Builders/Renderers/IStreamRenderer.cs b/QRCoder/Builders/Renderers/IStreamRenderer.cs new file mode 100644 index 00000000..2f4e3c44 --- /dev/null +++ b/QRCoder/Builders/Renderers/IStreamRenderer.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace QRCoder.Builders.Renderers +{ + public interface IStreamRenderer + { + MemoryStream ToStream(); + } +} diff --git a/QRCoder/Builders/Renderers/ITextRenderer.cs b/QRCoder/Builders/Renderers/ITextRenderer.cs new file mode 100644 index 00000000..897752af --- /dev/null +++ b/QRCoder/Builders/Renderers/ITextRenderer.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace QRCoder.Builders.Renderers +{ + public interface ITextRenderer + { + string ToString(); + } +} diff --git a/QRCoder/Builders/Renderers/Implementations/AsciiRenderer.cs b/QRCoder/Builders/Renderers/Implementations/AsciiRenderer.cs new file mode 100644 index 00000000..9d34f388 --- /dev/null +++ b/QRCoder/Builders/Renderers/Implementations/AsciiRenderer.cs @@ -0,0 +1,46 @@ +namespace QRCoder.Builders.Renderers.Implementations +{ + public class AsciiRenderer : RendererBase, ITextRenderer + { + private string _darkString = "██"; + private string _lightString = " "; + private int _repeatPerModule = 1; + private string _endOfLine = System.Environment.NewLine; + private bool _inverseDarkLight = false; + + public AsciiRenderer WithText(string darkString, string lightString) + { + _darkString = darkString; + _lightString = lightString; + return this; + } + + public AsciiRenderer WithRepeatPerModule(int repeatPerModule) + { + _repeatPerModule = repeatPerModule; + return this; + } + + public AsciiRenderer WithEndOfLine(string endOfLine) + { + _endOfLine = endOfLine; + return this; + } + + public AsciiRenderer WithInverseDarkLight() + { + _inverseDarkLight = true; + return this; + } + + public override string ToString() + { + return new AsciiQRCode(QrCodeData).GetGraphic( + _repeatPerModule, + _inverseDarkLight ? _lightString : _darkString, + _inverseDarkLight ? _darkString : _lightString, + QuietZone, + _endOfLine); + } + } +} diff --git a/QRCoder/Builders/Renderers/Implementations/PngRenderer.cs b/QRCoder/Builders/Renderers/Implementations/PngRenderer.cs new file mode 100644 index 00000000..21a24957 --- /dev/null +++ b/QRCoder/Builders/Renderers/Implementations/PngRenderer.cs @@ -0,0 +1,43 @@ +using System.IO; +using QRCoder.Builders.Payloads; + +namespace QRCoder.Builders.Renderers.Implementations +{ + public class PngRenderer : RendererBase, IConfigurablePixelsPerModule, IStreamRenderer + { + private int _pixelsPerModule = 10; + private byte[] _darkColor; + private byte[] _lightColor; + + int IConfigurablePixelsPerModule.PixelsPerModule { get => _pixelsPerModule; set => _pixelsPerModule = value; } + +#if !NETSTANDARD1_3 + public PngRenderer WithColors(System.Drawing.Color darkColor, System.Drawing.Color lightColor) + { + _darkColor = new byte[] { darkColor.R, darkColor.G, darkColor.B, darkColor.A }; + _lightColor = new byte[] { lightColor.R, lightColor.G, lightColor.B, lightColor.A }; + return this; + } +#endif + + public PngRenderer WithColors(byte[] darkColor, byte[] lightColor) + { + _darkColor = darkColor; + _lightColor = lightColor; + return this; + } + + public byte[] ToArray() + { + if (_darkColor == null && _lightColor == null) + return new PngByteQRCode(QrCodeData).GetGraphic(_pixelsPerModule, QuietZone); + return new PngByteQRCode(QrCodeData).GetGraphic(_pixelsPerModule, _darkColor, _lightColor, QuietZone); + } + + public MemoryStream ToStream() + { + var arr = ToArray(); + return new MemoryStream(arr, 0, arr.Length, false, true); + } + } +} diff --git a/QRCoder/Builders/Renderers/Implementations/SvgRenderer.cs b/QRCoder/Builders/Renderers/Implementations/SvgRenderer.cs new file mode 100644 index 00000000..30cc87ff --- /dev/null +++ b/QRCoder/Builders/Renderers/Implementations/SvgRenderer.cs @@ -0,0 +1,42 @@ +#if !NETSTANDARD1_3 +using System.Drawing; + +namespace QRCoder.Builders.Renderers.Implementations +{ + public class SvgRenderer : RendererBase, IConfigurablePixelsPerModule, ITextRenderer + { + private int _pixelsPerModule = 10; + private Color _darkColor; + private Color _lightColor; + private SvgQRCode.SvgLogo _logo; + private SvgQRCode.SizingMode _sizingMode = SvgQRCode.SizingMode.WidthHeightAttribute; + + int IConfigurablePixelsPerModule.PixelsPerModule { get => _pixelsPerModule; set => _pixelsPerModule = value; } + + public SvgRenderer WithColors(Color darkColor, Color lightColor) + { + _darkColor = darkColor; + _lightColor = lightColor; + return this; + } + + public SvgRenderer WithLogo(SvgQRCode.SvgLogo logo) + { + _logo = logo; + return this; + } + + public SvgRenderer WithSizingMode(SvgQRCode.SizingMode sizingMode) + { + _sizingMode = sizingMode; + return this; + } + + public override string ToString() + { + return new SvgQRCode(QrCodeData).GetGraphic( + _pixelsPerModule, _darkColor, _lightColor, QuietZone, _sizingMode, _logo); + } + } +} +#endif diff --git a/QRCoder/Builders/Renderers/Implementations/SystemDrawingRenderer.cs b/QRCoder/Builders/Renderers/Implementations/SystemDrawingRenderer.cs new file mode 100644 index 00000000..5d3025e2 --- /dev/null +++ b/QRCoder/Builders/Renderers/Implementations/SystemDrawingRenderer.cs @@ -0,0 +1,64 @@ +#if SYSTEM_DRAWING +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; + +namespace QRCoder.Builders.Renderers.Implementations +{ + public class SystemDrawingRenderer : RendererBase, IConfigurablePixelsPerModule, IStreamRenderer + { + private Color _darkColor = Color.Black; + private Color _lightColor = Color.White; + private int _pixelsPerModule; + private Bitmap _icon; + private double _iconSizePercent = 15; + private int _iconBorderWidth = 0; + private Color? _iconBackgroundColor; + private ImageFormat _imageFormat = ImageFormat.Png; + + int IConfigurablePixelsPerModule.PixelsPerModule { get => _pixelsPerModule; set => _pixelsPerModule = value; } + + public SystemDrawingRenderer WithColors(Color darkColor, Color lightColor) + { + _darkColor = darkColor; + _lightColor = lightColor; + return this; + } + + public SystemDrawingRenderer WithIcon(Bitmap icon, double iconSizePercent = 15, int iconBorderWidth = 0, Color? iconBackgroundColor = null) + { + _icon = icon; + _iconSizePercent = iconSizePercent; + _iconBorderWidth = iconBorderWidth; + _iconBackgroundColor = iconBackgroundColor; + return this; + } + + public SystemDrawingRenderer WithImageFormat(ImageFormat imageFormat) + { + _imageFormat = imageFormat; + return this; + } + + public Bitmap ToBitmap() + { + return new QRCode(QrCodeData).GetGraphic( + _pixelsPerModule, _darkColor, _lightColor, + _icon, (int)Math.Round(_iconSizePercent), _iconBorderWidth, + QuietZone, _iconBackgroundColor); + } + + public MemoryStream ToStream() + { + var ms = new MemoryStream(); + using (var bitmap = ToBitmap()) + { + bitmap.Save(ms, _imageFormat); + } + ms.Position = 0; + return ms; + } + } +} +#endif \ No newline at end of file diff --git a/QRCoder/Builders/Renderers/RendererBase.cs b/QRCoder/Builders/Renderers/RendererBase.cs new file mode 100644 index 00000000..7478e4fe --- /dev/null +++ b/QRCoder/Builders/Renderers/RendererBase.cs @@ -0,0 +1,13 @@ +using QRCoder.Builders.Payloads; + +namespace QRCoder.Builders.Renderers +{ + public abstract class RendererBase : IRenderer, IConfigurableQuietZones + { + protected QRCodeData QrCodeData { private set; get; } + + protected bool QuietZone { get; set; } = true; + bool IConfigurableQuietZones.QuietZone { get => QuietZone; set => QuietZone = value; } + IPayload IRenderer.Payload { set => QrCodeData = value.ToMatrix(); } + } +} diff --git a/QRCoder/Builders/Renderers/RendererExtensions.cs b/QRCoder/Builders/Renderers/RendererExtensions.cs new file mode 100644 index 00000000..3eb661ef --- /dev/null +++ b/QRCoder/Builders/Renderers/RendererExtensions.cs @@ -0,0 +1,104 @@ +using System; +using System.IO; +using System.Text; +using QRCoder.Builders.Renderers; + +namespace QRCoder +{ + public static class RendererExtensions + { + public static T WithQuietZone(this T payload, bool value) + where T : IConfigurableQuietZones + { + payload.QuietZone = value; + return payload; + } + + public static T WithPixelsPerModule(this T payload, int value) + where T : IConfigurablePixelsPerModule + { + payload.PixelsPerModule = value; + return payload; + } + + public static void ToStream(this IStreamRenderer streamRenderer, Stream stream) + { + var memoryStream = streamRenderer.ToStream(); + memoryStream.CopyTo(stream); + } + + public static byte[] ToArray(this IStreamRenderer streamRenderer) + { + var memoryStream = streamRenderer.ToStream(); +#if NETSTANDARD || NETCOREAPP // todo: target .NET Framework 4.6 or newer so this code path is supported + // by using TryGetBuffer, there is extremely small consequence to wrapping a byte[] in a MemoryStream temporarily + if (memoryStream.TryGetBuffer(out var buffer) && buffer.Count == buffer.Array.Length) + { + return buffer.Array; + } +#endif + return memoryStream.ToArray(); + } + + public static ArraySegment ToArraySegment(this IStreamRenderer streamRenderer) + { + var memoryStream = streamRenderer.ToStream(); +#if NETSTANDARD || NETCOREAPP // todo: target .NET Framework 4.6 or newer so this code path is supported + if (memoryStream.TryGetBuffer(out var buffer)) + { + return buffer; + } +#else + try + { + var buffer = memoryStream.GetBuffer(); + return new ArraySegment(buffer, 0, (int)memoryStream.Length); + } + catch { } +#endif + return new ArraySegment(memoryStream.ToArray()); + } + + public static string ToBase64String(this IStreamRenderer streamRenderer) + { + var data = ToArraySegment(streamRenderer); + return Convert.ToBase64String(data.Array, data.Offset, data.Count); + } + + public static void ToFile(this IStreamRenderer streamRenderer, string fileName) + { + var memoryStream = streamRenderer.ToStream(); + using (var file = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + memoryStream.CopyTo(file); + } + } + + public static void ToFile(this ITextRenderer textRenderer, string fileName, Encoding encoding = null) + { + File.WriteAllText(fileName, textRenderer.ToString(), encoding ?? Encoding.UTF8); + } + + public static void ToStream(this ITextRenderer textRenderer, Stream stream, Encoding encoding = null) + { + using (var writer = new StreamWriter(stream, encoding)) + { + writer.Write(textRenderer.ToString()); + writer.Flush(); + } + } + + public static MemoryStream ToStream(this ITextRenderer textRenderer, Encoding encoding = null) + { + var str = textRenderer.ToString(); + var ms = new MemoryStream(str.Length); + using (var writer = new StreamWriter(ms, encoding ?? Encoding.UTF8)) + { + writer.Write(str); + writer.Flush(); + } + ms.Position = 0; + return ms; + } + } +} diff --git a/QRCoder/QRCodeBuilder.cs b/QRCoder/QRCodeBuilder.cs new file mode 100644 index 00000000..4cb42c8d --- /dev/null +++ b/QRCoder/QRCodeBuilder.cs @@ -0,0 +1,52 @@ +using QRCoder.Builders.Payloads.Implementations; + +namespace QRCoder +{ + public static class QRCodeBuilder + { + public static StringPayload CreateUrl(string url) + { + return new StringPayload(url); + } + + public static StringPayload CreateSms(string number, PayloadGenerator.SMS.SMSEncoding encoding = PayloadGenerator.SMS.SMSEncoding.SMS) + { + return new StringPayload(new PayloadGenerator.SMS(number, encoding).ToString()); + } + + public static EmailPayload CreateEmail(string address) + { + return new EmailPayload(address); + } + + public static WiFiPayload CreateWiFi(string ssid) + { + return new WiFiPayload(ssid); + } + + public static WiFiPayload CreateWiFi(string ssid, string password, PayloadGenerator.WiFi.Authentication authentication) + { + return new WiFiPayload(ssid, password, authentication); + } + + public static StringPayload CreateBookmark(string url, string title) + { + return new StringPayload(new PayloadGenerator.Bookmark(url, title).ToString()); + } + + public static StringPayload CreateMMS(string number, PayloadGenerator.MMS.MMSEncoding encoding = PayloadGenerator.MMS.MMSEncoding.MMS) + { + return new StringPayload(new PayloadGenerator.MMS(number, encoding).ToString()); + } + + public static StringPayload CreateMMS(string number, string subject, PayloadGenerator.MMS.MMSEncoding encoding = PayloadGenerator.MMS.MMSEncoding.MMS) + { + return new StringPayload(new PayloadGenerator.MMS(number, subject, encoding).ToString()); + } + + public static StringPayload CreatePhoneNumber(string number) + { + return new StringPayload("tel:" + number); + } + } +} diff --git a/QRCoderTests/BuilderTests.cs b/QRCoderTests/BuilderTests.cs new file mode 100644 index 00000000..16390d3a --- /dev/null +++ b/QRCoderTests/BuilderTests.cs @@ -0,0 +1,90 @@ +#if NET5_0_OR_GREATER && SYSTEM_DRAWING +using QRCoder; +using QRCoder.Builders.Renderers.Implementations; +using Shouldly; +using Xunit; + +namespace QRCoderTests +{ + public class BuilderTests + { + [Fact] + public void EmailAsAscii() + { + var code = QRCodeBuilder.CreateEmail("test@microsoft.com") + .WithSubject("Testing") + .WithBody("Hello World!") + .WithErrorCorrection(QRCodeGenerator.ECCLevel.H) + .RenderWith() + .WithQuietZone(false) + .ToString(); + + code.ShouldBe(@"██████████████ ██ ████████████ ██████ ██ ████ ██ ██████████████ +██ ██ ██████ ██████████ ██████ ██ ██ ████ ██ ██ ██ ██ +██ ██████ ██ ██████ ████ ██ ████ ██ ██████ ██ ██ ██████ ██ +██ ██████ ██ ██ ██████ ██ ██████ ████ ████ ██ ██████ ██ +██ ██████ ██ ████████ ██ ████████████ ██ ██████ ██ ██████ ██ ██████ ██ +██ ██ ████████████████ ██ ████ ██ ██ ██ +██████████████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████████████ + ██████████████ ██████████ ██ ██ ██████ ██ + ██████ ██ ██ ██ ██████████ ████████████ ██████ ██ ██████ ██████ ██████ + ████ ██████████ ██ ████ ██ ████ ██████████ ██████ ██ ██ ██ + ██ ██ ████ ██ ██████ ████ ████ ██ ████ ██ ██ ████ ██ ██ ██ + ██ ██████ ██ ██ ████████ ██████████████████████ ████ ████ ████████████ ████ +████████ ████ ██ ██████ ██████ ████ ████ ████ ██████ ██ +██ ████ ██ ██ ████████████ ██ ██ ██████ ██████ ██████ ████ +██ ██ ██ ██ ████ ██ ██ ██ ████ ████ ██ ██ ████ ████ ██████ +██ ██ ████ ██ ██████ ████ ████████████████ ██ ██ ██████████████████ + ████ ████████ ██ ████████ ██ ████ ██████████ ██ ████ ████ + ██ ████ ██ ████ ██ ██████ ████████ ██████ ████ ██ +████ ██ ██████ ██████ ██████ ██████ ██ ██ ██ ██ ████ ██████ ██████ + ████ ████ ████ ██ ██████ ██ ████ ██████████ ██████████ ████████████ + ████████████████ ██ ████████████████ ██ ██ ████████████ ████ +██████████ ██ ████████ ████ ██████ ██ ██████ ████ ██ ██ ██ +██████████ ██ ████████████ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ +████ ██ ██ ██ ██ ██ ██████ ██ ████ ████ ██ ██ ██████████ + ██████████ ██ ██ ████████████████ ██ ██ ██████████████ ████ + ██ ████████ ██ ████ ████████ ████ ██ ██ ██ ██ ██ ██ + ██████████ ██ ██ ██ ████ ██ ██████ ████ ██████ ██ ████ ██ +████ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ████ ████ +████ ██████ ██ ██ ██ ████ ████ ██ ██ ██ ████ ████ + ██ ██ ██ ██ ████████ ██████████ ████ ██ ██ ██ ████ ██ +██████ ████████████ ████ ████ ██ ████ ██ ████ ████████████ ██████ +██ ██████ ██████ ██████ ████ ██████ ██ ██ ██ ██ ██████ ██ + ██ ██ ████ ████ ██ ████ ████ ██████████ ██████ ██ ██ ████ ██ +████ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██████ ██████ + ██ ██████ ██ ██ ██ ████████████ ██████ ██████████ ████████ + ████████ ██ ██ ██ ██████ ████ ██████ ██ ████ ████ ██████ +██ ████ ██ ████ ██████ ██████████████ ██████ ██████████ ████ + ██ ██ ██████ ████ ██ ██ ██ ████ ██ ██ ██ +██████████████ ██ ██ ██ ██ ██████ ██ ██ ████████ ████ ██ ██ ████ ██ +██ ██ ████ ██████ ████████ ████ ██████ ██████ +██ ██████ ██ ████ ████ ██ ██ ██████████ ██ ██ ██ ████████████ +██ ██████ ██ ████ ████ ██ ██████ ██████████ ████ ██ ████████████ +██ ██████ ██ ██ ████████████ ██ ████ ██ ██ ██ ██ ██ ████ ██ ████ +██ ██ ████ ██ ██ ██ ██ ████████ ██ ██ ██ ██ ██████ +██████████████ ██ ████████ ████ ██ ████ ██ ██ ██ ██ ", StringCompareShould.IgnoreLineEndings); + } + + [Fact] + public void PhoneAsBitmap() + { + var image = QRCodeBuilder.CreatePhoneNumber("1234567890") + .WithErrorCorrection(QRCodeGenerator.ECCLevel.H) + .RenderWith(20) + .WithQuietZone(false) + .ToBitmap(); + } + + [Fact] + public void MmsAsBase64() + { + var base64 = QRCodeBuilder.CreateMMS("1234567890", "Hello") + .RenderWith() + .ToBase64String(); + + base64.ShouldBe("iVBORw0KGgoAAAANSUhEUgAAAUoAAAFKAQAAAABTUiuoAAABdUlEQVR4nO2aSQ7DIAwAkfqAPilf50l9QCQK3qBtpPSGD8MhzTK5jIVtSEv7d9QCigEMYAADGMhhoNh49PNXsXtHP9NxgKYyIBftNdB2FqUOvfSnoHkM+DM703v9cgQbNLEBAyTOoMkNaA5dXwLNZsCTpte0sz+4ya+guwxEQ7LMxbveBXSTgTlKeUpDYjFdBmgWAx5EK2ytdl7afrsHmsuAtPgS2DEX9fBs/hJoKgM2+foaumrmtHSp0f3Mr6C7DUgHUiWS0efbPYs4aCYDkTm9xPkCwPasQPMYWLpETZVx+ClxoNsNSImzwibzbszAQdWfdQHofgM+A70D8bOLpAm63YD8RNKc4zq/gu40MMeyr6i9/8icoKkMeBhjs2PuVPmaDTSPgbkBrPMuvodZxQNNZSA+rnyNubkImtCA7n1IqpwrNdC0BmKTypdmoNkMeNL8+Fx5Kg+azEA0JL6kljpn/20DzWXgnwGKAQxgAAMYqNvLxhsMs1uBEKIWRQAAAABJRU5ErkJggg=="); + } + } +} +#endif \ No newline at end of file