diff --git a/QRCoder/ArtQRCode.cs b/QRCoder/ArtQRCode.cs index f26aa838..f616164d 100644 --- a/QRCoder/ArtQRCode.cs +++ b/QRCoder/ArtQRCode.cs @@ -3,6 +3,8 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using static QRCoder.ArtQRCode; +using static QRCoder.QRCodeGenerator; // pull request raised to extend library used. namespace QRCoder @@ -14,32 +16,59 @@ public class ArtQRCode : AbstractQRCode, IDisposable /// public ArtQRCode() { } + /// + /// Creates new ArtQrCode object + /// + /// QRCodeData generated by the QRCodeGenerator public ArtQRCode(QRCodeData data) : base(data) { } + /// + /// Renders an art-style QR code with dots as modules. (With default settings: DarkColor=Black, LightColor=White, Background=Transparent, QuietZone=true) + /// + /// Amount of px each dark/light module of the QR code shall take place in the final QR code image + /// QRCode graphic as bitmap public Bitmap GetGraphic(int pixelsPerModule) { - return this.GetGraphic(pixelsPerModule, (pixelsPerModule * 8) / 10, Color.Black, Color.White); + return this.GetGraphic(pixelsPerModule, Color.Black, Color.White, Color.Transparent); } + /// + /// Renders an art-style QR code with dots as modules and a background image (With default settings: DarkColor=Black, LightColor=White, Background=Transparent, QuietZone=true) + /// + /// A bitmap object that will be used as background picture + /// QRCode graphic as bitmap public Bitmap GetGraphic(Bitmap backgroundImage = null) { - return this.GetGraphic(10, 7, Color.Black, Color.White, backgroundImage: backgroundImage); + return this.GetGraphic(10, Color.Black, Color.White, Color.Transparent, backgroundImage: backgroundImage); } - public Bitmap GetGraphic( - int pixelsPerModule, - int pixelSize, - Color darkColor, - Color lightColor, - bool drawQuietZones = false, - Bitmap reticleImage = null, - Bitmap backgroundImage = null) + /// + /// Renders an art-style QR code with dots as modules and various user settings + /// + /// Amount of px each dark/light module of the QR code shall take place in the final QR code image + /// Color of the dark modules + /// Color of the light modules + /// Color of the background + /// A bitmap object that will be used as background picture + /// Value between 0.0 to 1.0 that defines how big the module dots are. The bigger the value, the less round the dots will be. + /// If true a white border is drawn around the whole QR Code + /// Style of the quiet zones + /// Style of the background image (if set). Fill=spanning complete graphic; DataAreaOnly=Don't paint background into quietzone + /// Optional image that should be used instead of the default finder patterns + /// QRCode graphic as bitmap + public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Color backgroundColor, Bitmap backgroundImage = null, double pixelSizeFactor = 0.8, + bool drawQuietZones = true, QuietZoneStyle quietZoneRenderingStyle = QuietZoneStyle.Dotted, + BackgroundImageStyle backgroundImageStyle = BackgroundImageStyle.DataAreaOnly, Bitmap finderPatternImage = null) { - var numModules = this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8); + if (pixelSizeFactor > 1) + throw new Exception("The parameter pixelSize must be between 0 and 1. (0-100%)"); + int pixelSize = (int)Math.Min(pixelsPerModule, Math.Floor(pixelsPerModule / pixelSizeFactor)); + + var numModules = QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8); var offset = (drawQuietZones ? 0 : 4); var size = numModules * pixelsPerModule; - var bitmap = Resize(backgroundImage,size) ?? new Bitmap(size, size); + var bitmap = new Bitmap(size, size); using (var graphics = Graphics.FromImage(bitmap)) { @@ -47,14 +76,21 @@ public Bitmap GetGraphic( { using (var darkBrush = new SolidBrush(darkColor)) { - // make background transparent if you don't have an image -- not sure this is needed - if (backgroundImage == null) + // make background transparent + using (var brush = new SolidBrush(backgroundColor)) + graphics.FillRectangle(brush, new Rectangle(0, 0, size, size)); + //Render background if set + if (backgroundImage != null) { - using (var brush = new SolidBrush(Color.Transparent)) + if (backgroundImageStyle == BackgroundImageStyle.Fill) + graphics.DrawImage(Resize(backgroundImage, size), 0, 0); + else if (backgroundImageStyle == BackgroundImageStyle.DataAreaOnly) { - graphics.FillRectangle(brush, new Rectangle(0, 0, size, size)); + var bgOffset = 4 - offset; + graphics.DrawImage(Resize(backgroundImage, size - (2 * bgOffset * pixelsPerModule)), 0 + (bgOffset * pixelsPerModule), (bgOffset * pixelsPerModule)); } } + var darkModulePixel = MakeDotPixel(pixelsPerModule, pixelSize, darkBrush); var lightModulePixel = MakeDotPixel(pixelsPerModule, pixelSize, lightBrush); @@ -69,21 +105,22 @@ public Bitmap GetGraphic( var solidBrush = pixelIsDark ? darkBrush : lightBrush; var pixelImage = pixelIsDark ? darkModulePixel : lightModulePixel; - if (!IsPartOfReticle(x, y, numModules, offset)) - graphics.DrawImage(pixelImage, rectangleF); - else if (reticleImage == null) + if (!IsPartOfFinderPattern(x, y, numModules, offset)) + if (drawQuietZones && quietZoneRenderingStyle == QuietZoneStyle.Flat && IsPartOfQuietZone(x, y, numModules)) + graphics.FillRectangle(solidBrush, rectangleF); + else + graphics.DrawImage(pixelImage, rectangleF); + else if (finderPatternImage == null) graphics.FillRectangle(solidBrush, rectangleF); } } - - if (reticleImage != null) + if (finderPatternImage != null) { - var reticleSize = 7 * pixelsPerModule; - graphics.DrawImage(reticleImage, new Rectangle(0, 0, reticleSize, reticleSize)); - graphics.DrawImage(reticleImage, new Rectangle(size - reticleSize, 0, reticleSize, reticleSize)); - graphics.DrawImage(reticleImage, new Rectangle(0, size - reticleSize, reticleSize, reticleSize)); + var finderPatternSize = 7 * pixelsPerModule; + graphics.DrawImage(finderPatternImage, new Rectangle(0, 0, finderPatternSize, finderPatternSize)); + graphics.DrawImage(finderPatternImage, new Rectangle(size - finderPatternSize, 0, finderPatternSize, finderPatternSize)); + graphics.DrawImage(finderPatternImage, new Rectangle(0, size - finderPatternSize, finderPatternSize, finderPatternSize)); } - graphics.Save(); } } @@ -94,12 +131,12 @@ public Bitmap GetGraphic( /// /// If the pixelSize is bigger than the pixelsPerModule or may end up filling the Module making a traditional QR code. /// - /// - /// - /// + /// Pixels used per module rendered + /// Size of the dots + /// Color of the pixels /// private Bitmap MakeDotPixel(int pixelsPerModule, int pixelSize, SolidBrush brush) - { + { // draw a dot var bitmap = new Bitmap(pixelSize, pixelSize); using (var graphics = Graphics.FromImage(bitmap)) @@ -124,22 +161,50 @@ private Bitmap MakeDotPixel(int pixelsPerModule, int pixelSize, SolidBrush brush return cropped; } - private bool IsPartOfReticle(int x, int y, int numModules, int offset) + + /// + /// Checks if a given module(-position) is part of the quietzone of a QR code + /// + /// X position + /// Y position + /// Total number of modules per row + /// true, if position is part of quiet zone + private bool IsPartOfQuietZone(int x, int y, int numModules) + { + return + x < 4 || //left + y < 4 || //top + x > numModules - 5 || //right + y > numModules - 5; //bottom + } + + + /// + /// Checks if a given module(-position) is part of one of the three finder patterns of a QR code + /// + /// X position + /// Y position + /// Total number of modules per row + /// Offset in modules (usually depending on drawQuietZones parameter) + /// true, if position is part of any finder pattern + private bool IsPartOfFinderPattern(int x, int y, int numModules, int offset) { var cornerSize = 11 - offset; + var outerLimitLow = (numModules - cornerSize - 1); + var outerLimitHigh = outerLimitLow + 8; + var invertedOffset = 4 - offset; return - (x < cornerSize && y < cornerSize) || - (x > (numModules - cornerSize - 1) && y < cornerSize) || - (x < cornerSize && y > (numModules - cornerSize - 1)); + (x >= invertedOffset && x < cornerSize && y >= invertedOffset && y < cornerSize) || //Top-left finder pattern + (x > outerLimitLow && x < outerLimitHigh && y >= invertedOffset && y < cornerSize) || //Top-right finder pattern + (x >= invertedOffset && x < cornerSize && y > outerLimitLow && y < outerLimitHigh); //Bottom-left finder pattern } /// /// Resize to a square bitmap, but maintain the aspect ratio by padding transparently. /// - /// /// /// - /// + /// Resized image as bitmap private Bitmap Resize(Bitmap image, int newSize) { if (image == null) return null; @@ -167,9 +232,60 @@ private Bitmap Resize(Bitmap image, int newSize) graphics.DrawImage(scaledImage, new Rectangle(offsetX, offsetY, scaledWidth, scaledHeight)); } } - return bm; } + + /// + /// Defines how the quiet zones shall be rendered. + /// + public enum QuietZoneStyle + { + Dotted, + Flat + } + + /// + /// Defines how the background image (if set) shall be rendered. + /// + public enum BackgroundImageStyle + { + Fill, + DataAreaOnly + } + } + + public static class ArtQRCodeHelper + { + /// + /// Helper function to create an ArtQRCode graphic with a single function call + /// + /// Text/payload to be encoded inside the QR code + /// Amount of px each dark/light module of the QR code shall take place in the final QR code image + /// Color of the dark modules + /// Color of the light modules + /// Color of the background + /// The level of error correction data + /// Shall the generator be forced to work in UTF-8 mode? + /// Should the byte-order-mark be used? + /// Which ECI mode shall be used? + /// Set fixed QR code target version. + /// A bitmap object that will be used as background picture + /// Value between 0.0 to 1.0 that defines how big the module dots are. The bigger the value, the less round the dots will be. + /// If true a white border is drawn around the whole QR Code + /// Style of the quiet zones + /// Style of the background image (if set). Fill=spanning complete graphic; DataAreaOnly=Don't paint background into quietzone + /// Optional image that should be used instead of the default finder patterns + /// QRCode graphic as bitmap + public static Bitmap GetQRCode(string plainText, int pixelsPerModule, Color darkColor, Color lightColor, Color backgroundColor, ECCLevel eccLevel, bool forceUtf8 = false, + bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, Bitmap backgroundImage = null, double pixelSizeFactor = 0.8, + bool drawQuietZones = true, QuietZoneStyle quietZoneRenderingStyle = QuietZoneStyle.Flat, + BackgroundImageStyle backgroundImageStyle = BackgroundImageStyle.DataAreaOnly, Bitmap finderPatternImage = null) + { + using (var qrGenerator = new QRCodeGenerator()) + using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion)) + using (var qrCode = new ArtQRCode(qrCodeData)) + return qrCode.GetGraphic(pixelsPerModule, darkColor, lightColor, backgroundColor, backgroundImage, pixelSizeFactor, drawQuietZones, quietZoneRenderingStyle, backgroundImageStyle, finderPatternImage); + } } } diff --git a/QRCoderTests/ArtQRCodeRendererTests.cs b/QRCoderTests/ArtQRCodeRendererTests.cs new file mode 100644 index 00000000..f60f1db6 --- /dev/null +++ b/QRCoderTests/ArtQRCodeRendererTests.cs @@ -0,0 +1,123 @@ +#if !NETCOREAPP1_1 + +using Xunit; +using QRCoder; +using Shouldly; +using System.Drawing; +using QRCoderTests.Helpers.XUnitExtenstions; +using QRCoderTests.Helpers; + +namespace QRCoderTests +{ + + public class ArtQRCodeRendererTests + { + + + [Fact] + [Category("QRRenderer/ArtQRCode")] + public void can_create_standard_qrcode_graphic() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var bmp = new ArtQRCode(data).GetGraphic(10); + + var result = HelperFunctions.BitmapToHash(bmp); +#if NET35_OR_GREATER || NET40_OR_GREATER + result.ShouldBe("11ebdda91b9632d016798cb6de2f5339"); +#else + result.ShouldBe("cb38c3156eaf13cdfba699bdafc3a84c"); +#endif + } + + [Fact] + [Category("QRRenderer/ArtQRCode")] + public void can_create_standard_qrcode_graphic_with_custom_finder() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var finder = new Bitmap(15, 15); + var bmp = new ArtQRCode(data).GetGraphic(10, Color.Black, Color.White, Color.Transparent, finderPatternImage: finder); + + var result = HelperFunctions.BitmapToHash(bmp); +#if NET35_OR_GREATER || NET40_OR_GREATER + result.ShouldBe("c54a7389ae995abc838f0d228acc3bad"); +#else + result.ShouldBe("1102c0c6f235eaf4c3ac639f82f17bfa"); +#endif + } + + [Fact] + [Category("QRRenderer/ArtQRCode")] + public void can_create_standard_qrcode_graphic_without_quietzone() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var bmp = new ArtQRCode(data).GetGraphic(10, Color.Black, Color.White, Color.Transparent, drawQuietZones: false); + + var result = HelperFunctions.BitmapToHash(bmp); +#if NET35_OR_GREATER || NET40_OR_GREATER + result.ShouldBe("550f31b988ff12d5f8429ef19d9d5a0c"); +#else + result.ShouldBe("632315c8695416fc82fe06a202688433"); +#endif + } + + [Fact] + [Category("QRRenderer/ArtQRCode")] + public void can_create_standard_qrcode_graphic_with_background() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var bmp = new ArtQRCode(data).GetGraphic((Bitmap)Image.FromFile(HelperFunctions.GetAssemblyPath() + "\\assets\\noun_software engineer_2909346.png")); + //Used logo is licensed under public domain. Ref.: https://thenounproject.com/Iconathon1/collection/redefining-women/?i=2909346 + + var result = HelperFunctions.BitmapToHash(bmp); + +#if NET35_OR_GREATER || NET40_OR_GREATER + result.ShouldBe("2caa9c0ee8fcb4a93841debb58cf41bc"); +#else + result.ShouldBe("bbea08507282773175cfe7b52f0ddae4"); +#endif + } + + [Fact] + [Category("QRRenderer/ArtQRCode")] + public void should_throw_pixelfactor_oor_exception() + { + var gen = new QRCodeGenerator(); + var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); + var aCode = new ArtQRCode(data); + + var exception = Record.Exception(() => aCode.GetGraphic(10, Color.Black, Color.White, Color.Transparent, pixelSizeFactor: 2)); + Assert.NotNull(exception); + Assert.IsType(exception); + exception.Message.ShouldBe("The parameter pixelSize must be between 0 and 1. (0-100%)"); + } + + [Fact] + [Category("QRRenderer/ArtQRCode")] + public void can_instantate_parameterless() + { + var asciiCode = new ArtQRCode(); + asciiCode.ShouldNotBeNull(); + asciiCode.ShouldBeOfType(); + } + + [Fact] + [Category("QRRenderer/ArtQRCode")] + public void can_render_artqrcode_from_helper() + { + //Create QR code + var bmp = ArtQRCodeHelper.GetQRCode("A", 10, Color.Black, Color.White, Color.Transparent, QRCodeGenerator.ECCLevel.L); + + var result = HelperFunctions.BitmapToHash(bmp); +#if NET35_OR_GREATER || NET40_OR_GREATER + result.ShouldBe("fea51114bc4ff893542a1c0574c82a07"); +#else + result.ShouldBe("57ecaa9bdeadcdcbeac8a19d734907ff"); +#endif + } + } +} +#endif \ No newline at end of file diff --git a/QRCoderTests/AsciiQRCodeRendererTests.cs b/QRCoderTests/AsciiQRCodeRendererTests.cs index 6b0517a0..7ac2656b 100644 --- a/QRCoderTests/AsciiQRCodeRendererTests.cs +++ b/QRCoderTests/AsciiQRCodeRendererTests.cs @@ -1,7 +1,7 @@ using Xunit; using QRCoder; using Shouldly; -using QRCoderTests.XUnitExtenstions; +using QRCoderTests.Helpers.XUnitExtenstions; namespace QRCoderTests @@ -67,9 +67,7 @@ public void can_render_ascii_qrcode_from_helper() { var targetCode = " \n \n \n \n \n \n \n \n XXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXX \n XXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXX \n XX XX XXXXXX XX XX XX \n XX XX XXXXXX XX XX XX \n XX XXXXXX XX XXXXXXXX XX XXXXXX XX \n XX XXXXXX XX XXXXXXXX XX XXXXXX XX \n XX XXXXXX XX XXXX XX XXXXXX XX \n XX XXXXXX XX XXXX XX XXXXXX XX \n XX XXXXXX XX XX XX XX XXXXXX XX \n XX XXXXXX XX XX XX XX XXXXXX XX \n XX XX XX XX XX \n XX XX XX XX XX \n XXXXXXXXXXXXXX XX XX XX XXXXXXXXXXXXXX \n XXXXXXXXXXXXXX XX XX XX XXXXXXXXXXXXXX \n XXXXXXXX \n XXXXXXXX \n XX XXXXXX XXXXXX XX XX XX \n XX XXXXXX XXXXXX XX XX XX \n XX XXXXXX XXXX XXXXXXXX XXXXXX XX \n XX XXXXXX XXXX XXXXXXXX XXXXXX XX \n XX XX XX XX XX XX \n XX XX XX XX XX XX \n XX XX XX XX XXXXXX \n XX XX XX XX XXXXXX \n XX XXXXXXXX XXXX XX XXXXXXXX XX \n XX XXXXXXXX XXXX XX XXXXXXXX XX \n XX XXXXXXXX XXXX \n XX XXXXXXXX XXXX \n XXXXXXXXXXXXXX XXXXXXXX XX XXXXXX \n XXXXXXXXXXXXXX XXXXXXXX XX XXXXXX \n XX XX XXXXXX XXXXXXXX \n XX XX XXXXXX XXXXXXXX \n XX XXXXXX XX XX XXXX XX XXXX \n XX XXXXXX XX XX XXXX XX XXXX \n XX XXXXXX XX XXXX XXXXXXXX \n XX XXXXXX XX XXXX XXXXXXXX \n XX XXXXXX XX XX XXXXXXXX XX XXXXXX \n XX XXXXXX XX XX XXXXXXXX XX XXXXXX \n XX XX XX XXXX XX \n XX XX XX XXXX XX \n XXXXXXXXXXXXXX XX XXXXXX XXXX XXXX \n XXXXXXXXXXXXXX XX XXXXXX XXXX XXXX \n \n \n \n \n \n \n \n "; - //Create QR code - var gen = new QRCodeGenerator(); - var data = gen.CreateQrCode("A", QRCodeGenerator.ECCLevel.Q); + //Create QR code var asciiCode = AsciiQRCodeHelper.GetQRCode("A", 2, "X", " ", QRCodeGenerator.ECCLevel.Q); asciiCode.ShouldBe(targetCode); } diff --git a/QRCoderTests/CategoryDiscoverer.cs b/QRCoderTests/Helpers/CategoryDiscoverer.cs similarity index 95% rename from QRCoderTests/CategoryDiscoverer.cs rename to QRCoderTests/Helpers/CategoryDiscoverer.cs index 8a04d1b3..0593cb1a 100644 --- a/QRCoderTests/CategoryDiscoverer.cs +++ b/QRCoderTests/Helpers/CategoryDiscoverer.cs @@ -6,7 +6,7 @@ #endif using Xunit.Sdk; -namespace QRCoderTests.XUnitExtenstions +namespace QRCoderTests.Helpers.XUnitExtenstions { #if NET35 || NET452 [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] diff --git a/QRCoderTests/Helpers/HelperFunctions.cs b/QRCoderTests/Helpers/HelperFunctions.cs new file mode 100644 index 00000000..d8f7e78c --- /dev/null +++ b/QRCoderTests/Helpers/HelperFunctions.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Security.Cryptography; +#if !NETCOREAPP1_1 +using System.Drawing; +#endif + +namespace QRCoderTests.Helpers +{ + public static class HelperFunctions + { + +#if !NETCOREAPP1_1 + public static string GetAssemblyPath() + { + return +#if NET5_0 + AppDomain.CurrentDomain.BaseDirectory; +#else + Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).Replace("file:\\", ""); +#endif + } +#endif + + +#if !NETCOREAPP1_1 + public static string BitmapToHash(Bitmap bmp) + { + byte[] imgBytes = null; + using (var ms = new MemoryStream()) + { + bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png); + imgBytes = ms.ToArray(); + ms.Dispose(); + } + var md5 = new MD5CryptoServiceProvider(); + var hash = md5.ComputeHash(imgBytes); + return BitConverter.ToString(hash).Replace("-", "").ToLower(); + } +#endif + + } +} diff --git a/QRCoderTests/PayloadGeneratorTests.cs b/QRCoderTests/PayloadGeneratorTests.cs index d82b7f98..f6849440 100644 --- a/QRCoderTests/PayloadGeneratorTests.cs +++ b/QRCoderTests/PayloadGeneratorTests.cs @@ -4,7 +4,7 @@ using Shouldly; using System.Globalization; using System.Threading; -using QRCoderTests.XUnitExtenstions; +using QRCoderTests.Helpers.XUnitExtenstions; using static QRCoder.PayloadGenerator.BezahlCode; using static QRCoder.PayloadGenerator.SwissQrCode.Reference; using System.Reflection; diff --git a/QRCoderTests/QRCodeRendererTests.cs b/QRCoderTests/QRCodeRendererTests.cs index d6c9362d..44b5ac3c 100644 --- a/QRCoderTests/QRCodeRendererTests.cs +++ b/QRCoderTests/QRCodeRendererTests.cs @@ -2,9 +2,10 @@ using Xunit; using QRCoder; using Shouldly; -using QRCoderTests.XUnitExtenstions; using System.IO; using System.Security.Cryptography; +using QRCoderTests.Helpers.XUnitExtenstions; +using QRCoderTests.Helpers; #if !NETCOREAPP1_1 using System.Drawing; #endif @@ -24,31 +25,14 @@ public void can_create_standard_qrcode_graphic() var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); var bmp = new QRCode(data).GetGraphic(10); - var ms = new MemoryStream(); - bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Gif); - var imgBytes = ms.ToArray(); - var md5 = new MD5CryptoServiceProvider(); - var hash = md5.ComputeHash(imgBytes); - var result = BitConverter.ToString(hash).Replace("-", "").ToLower(); - ms.Dispose(); - - result.ShouldBe("a76c8a72e95df3368717663c6be41b3e"); + var result = HelperFunctions.BitmapToHash(bmp); + result.ShouldBe("e8c61b8f0455924fe08ba68686d0d296"); } #endif #if !NETCOREAPP1_1 && !NETCOREAPP2_0 - private string GetAssemblyPath() - { - return -#if NET5_0 - AppDomain.CurrentDomain.BaseDirectory; -#else - Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).Replace("file:\\", ""); -#endif - } - [Fact] [Category("QRRenderer/QRCode")] public void can_create_qrcode_with_transparent_logo_graphic() @@ -57,15 +41,15 @@ public void can_create_qrcode_with_transparent_logo_graphic() var gen = new QRCodeGenerator(); var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); - var bmp = new QRCode(data).GetGraphic(10, Color.Black, Color.Transparent, icon: (Bitmap)Image.FromFile(GetAssemblyPath() + "\\assets\\noun_software engineer_2909346.png")); + var bmp = new QRCode(data).GetGraphic(10, Color.Black, Color.Transparent, icon: (Bitmap)Image.FromFile(HelperFunctions.GetAssemblyPath() + "\\assets\\noun_software engineer_2909346.png")); //Used logo is licensed under public domain. Ref.: https://thenounproject.com/Iconathon1/collection/redefining-women/?i=2909346 - var imgBytes = PixelsToAveragedByteArray(bmp); - var md5 = new MD5CryptoServiceProvider(); - var hash = md5.ComputeHash(imgBytes); - var result = BitConverter.ToString(hash).Replace("-", "").ToLower(); - - result.ShouldBe("33c250bf306b7cbbd3dd71b6029b8784"); + var result = HelperFunctions.BitmapToHash(bmp); +#if NET35_OR_GREATER || NET40_OR_GREATER + result.ShouldBe("ee65d96c3013f6032b561cc768251eef"); +#else + result.ShouldBe("150f8fc7dae4487ba2887d2b2bea1c25"); +#endif } [Fact] @@ -75,18 +59,18 @@ public void can_create_qrcode_with_non_transparent_logo_graphic() //Create QR code var gen = new QRCodeGenerator(); var data = gen.CreateQrCode("This is a quick test! 123#?", QRCodeGenerator.ECCLevel.H); - var bmp = new QRCode(data).GetGraphic(10, Color.Black, Color.White, icon: (Bitmap)Bitmap.FromFile(GetAssemblyPath() + "\\assets\\noun_software engineer_2909346.png")); + var bmp = new QRCode(data).GetGraphic(10, Color.Black, Color.White, icon: (Bitmap)Bitmap.FromFile(HelperFunctions.GetAssemblyPath() + "\\assets\\noun_software engineer_2909346.png")); //Used logo is licensed under public domain. Ref.: https://thenounproject.com/Iconathon1/collection/redefining-women/?i=2909346 - var imgBytes = PixelsToAveragedByteArray(bmp); - var md5 = new MD5CryptoServiceProvider(); - var hash = md5.ComputeHash(imgBytes); - var result = BitConverter.ToString(hash).Replace("-", "").ToLower(); - - result.ShouldBe("33c250bf306b7cbbd3dd71b6029b8784"); + var result = HelperFunctions.BitmapToHash(bmp); +#if NET35_OR_GREATER || NET40_OR_GREATER + result.ShouldBe("1d718f06f904af4a46748f02af2d4eec"); +#else + result.ShouldBe("c46a7ec51bf978d7a882059c322ca69d"); +#endif } - + /* private static byte[] PixelsToAveragedByteArray(Bitmap bmp) { //Re-color @@ -107,7 +91,7 @@ private static byte[] PixelsToAveragedByteArray(Bitmap bmp) } return bytes.ToArray(); } - + */ #endif } } \ No newline at end of file diff --git a/QRCoderTests/QRGeneratorTests.cs b/QRCoderTests/QRGeneratorTests.cs index 16073f12..cd016289 100644 --- a/QRCoderTests/QRGeneratorTests.cs +++ b/QRCoderTests/QRGeneratorTests.cs @@ -1,5 +1,5 @@ using QRCoder; -using QRCoderTests.XUnitExtenstions; +using QRCoderTests.Helpers.XUnitExtenstions; using Shouldly; using System.Collections.Generic; using System.Reflection; diff --git a/QRCoderTests/SvgQRCodeRendererTests.cs b/QRCoderTests/SvgQRCodeRendererTests.cs index 3da99c12..65ef6cac 100644 --- a/QRCoderTests/SvgQRCodeRendererTests.cs +++ b/QRCoderTests/SvgQRCodeRendererTests.cs @@ -2,7 +2,7 @@ using Xunit; using QRCoder; using Shouldly; -using QRCoderTests.XUnitExtenstions; +using QRCoderTests.Helpers.XUnitExtenstions; using System.IO; using System.Security.Cryptography; #if !NETCOREAPP1_1 diff --git a/readme.md b/readme.md index c0de14af..64111f94 100644 --- a/readme.md +++ b/readme.md @@ -73,18 +73,19 @@ There are a plenty of other options. So feel free to read more on that in our wi Besides the normal QRCode class (which is shown in the example above) for creating QR codes in Bitmap format, there are some more QR code rendering classes, each for another special purpose. -* [QRCode*](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#21-qrcode-renderer-in-detail) -* [AsciiQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#22-asciiqrcode-renderer-in-detail) -* [Base64QRCode*](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#23-base64qrcode-renderer-in-detail) -* [BitmapByteQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#24-bitmapbyteqrcode-renderer-in-detail) -* [PdfByteQRCode*](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#210-pdfbyteqrcode-renderer-in-detail) -* [PngByteQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#25-pngbyteqrcode-renderer-in-detail) -* [PostscriptQRCode*](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#29-postscriptqrcode-renderer-in-detail) -* [SvgQRCode*](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#26-svgqrcode-renderer-in-detail) -* [UnityQRCode**](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#27-unityqrcode-renderer-in-detail) -* [XamlQRCode*](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#28-xamlqrcode-renderer-in-detail) - -*(*) - These classes are only available in the .NET Framework/.NET Standard version. If you use the PCL version (e.g. for Universal apps), you have to use either BitmapByteQRCode or PngByteQRCode classes.* +* [QRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#21-qrcode-renderer-in-detail) +* [ArtQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#211-artqrcode-renderer-in-detail) +* [AsciiQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#22-asciiqrcode-renderer-in-detail) +* [Base64QRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#23-base64qrcode-renderer-in-detail) +* [BitmapByteQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#24-bitmapbyteqrcode-renderer-in-detail) +* [PdfByteQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#210-pdfbyteqrcode-renderer-in-detail) +* [PngByteQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#25-pngbyteqrcode-renderer-in-detail) +* [PostscriptQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#29-postscriptqrcode-renderer-in-detail) +* [SvgQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#26-svgqrcode-renderer-in-detail) +* [UnityQRCode*](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#27-unityqrcode-renderer-in-detail) +* [XamlQRCode](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers#28-xamlqrcode-renderer-in-detail) + +*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.* *(**) - This class is hosted in an own package ([QRCoder.Unity](https://github.com/codebude/QRCoder.Unity)).*