You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
6.3 KiB

  1. #if NET40 || NET461
  2. using System.Drawing;
  3. using System.Drawing.Drawing2D;
  4. namespace Apewer.Internals.QrCode
  5. {
  6. using System;
  7. internal class QRCode : AbstractQRCode, IDisposable
  8. {
  9. /// <summary>
  10. /// Constructor without params to be used in COM Objects connections
  11. /// </summary>
  12. public QRCode() { }
  13. public QRCode(QRCodeData data) : base(data) { }
  14. public Bitmap GetGraphic(int pixelsPerModule)
  15. {
  16. return this.GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
  17. }
  18. public Bitmap GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true)
  19. {
  20. return this.GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), drawQuietZones);
  21. }
  22. public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true)
  23. {
  24. var size = (this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8)) * pixelsPerModule;
  25. var offset = drawQuietZones ? 0 : 4 * pixelsPerModule;
  26. var bmp = new Bitmap(size, size);
  27. var gfx = Graphics.FromImage(bmp);
  28. gfx.Clear(lightColor);
  29. for (var x = 0; x < size + offset; x = x + pixelsPerModule)
  30. {
  31. for (var y = 0; y < size + offset; y = y + pixelsPerModule)
  32. {
  33. var module = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1];
  34. if (module)
  35. {
  36. gfx.FillRectangle(new SolidBrush(darkColor), new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
  37. }
  38. else
  39. {
  40. gfx.FillRectangle(new SolidBrush(lightColor), new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
  41. }
  42. }
  43. }
  44. gfx.Save();
  45. return bmp;
  46. }
  47. public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Bitmap icon = null, int iconSizePercent = 15, int iconBorderWidth = 6, bool drawQuietZones = true)
  48. {
  49. var size = (this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8)) * pixelsPerModule;
  50. var offset = drawQuietZones ? 0 : 4 * pixelsPerModule;
  51. var bmp = new Bitmap(size, size, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  52. var gfx = Graphics.FromImage(bmp);
  53. gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
  54. gfx.CompositingQuality = CompositingQuality.HighQuality;
  55. gfx.Clear(lightColor);
  56. var drawIconFlag = icon != null && iconSizePercent > 0 && iconSizePercent <= 100;
  57. GraphicsPath iconPath = null;
  58. float iconDestWidth = 0, iconDestHeight = 0, iconX = 0, iconY = 0;
  59. if (drawIconFlag)
  60. {
  61. iconDestWidth = iconSizePercent * bmp.Width / 100f;
  62. iconDestHeight = drawIconFlag ? iconDestWidth * icon.Height / icon.Width : 0;
  63. iconX = (bmp.Width - iconDestWidth) / 2;
  64. iconY = (bmp.Height - iconDestHeight) / 2;
  65. var centerDest = new RectangleF(iconX - iconBorderWidth, iconY - iconBorderWidth, iconDestWidth + iconBorderWidth * 2, iconDestHeight + iconBorderWidth * 2);
  66. iconPath = this.CreateRoundedRectanglePath(centerDest, iconBorderWidth * 2);
  67. }
  68. var lightBrush = new SolidBrush(lightColor);
  69. var darkBrush = new SolidBrush(darkColor);
  70. for (var x = 0; x < size + offset; x = x + pixelsPerModule)
  71. {
  72. for (var y = 0; y < size + offset; y = y + pixelsPerModule)
  73. {
  74. var module = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1];
  75. if (module)
  76. {
  77. var r = new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule);
  78. if (drawIconFlag)
  79. {
  80. var region = new Region(r);
  81. region.Exclude(iconPath);
  82. gfx.FillRegion(darkBrush, region);
  83. }
  84. else
  85. {
  86. gfx.FillRectangle(darkBrush, r);
  87. }
  88. }
  89. else
  90. gfx.FillRectangle(lightBrush, new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
  91. }
  92. }
  93. if (drawIconFlag)
  94. {
  95. var iconDestRect = new RectangleF(iconX, iconY, iconDestWidth, iconDestHeight);
  96. gfx.DrawImage(icon, iconDestRect, new RectangleF(0, 0, icon.Width, icon.Height), GraphicsUnit.Pixel);
  97. }
  98. gfx.Save();
  99. return bmp;
  100. }
  101. internal GraphicsPath CreateRoundedRectanglePath(RectangleF rect, int cornerRadius)
  102. {
  103. var roundedRect = new GraphicsPath();
  104. roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
  105. roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);
  106. roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
  107. roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);
  108. roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
  109. roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom);
  110. roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
  111. roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
  112. roundedRect.CloseFigure();
  113. return roundedRect;
  114. }
  115. }
  116. }
  117. #endif