GithubGravatarGenerator.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using System;
  2. using System.Globalization;
  3. using System.Security.Cryptography;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Media;
  7. using System.Windows.Shapes;
  8. using HandyControl.Controls;
  9. namespace HandyControl.Tools;
  10. public class GithubGravatarGenerator : IGravatarGenerator
  11. {
  12. private const int RenderDataMaxLength = 15;
  13. public object GetGravatar(string id)
  14. {
  15. var hashcode = GetHashCode(id);
  16. var renderData = GetRenderData(hashcode);
  17. var renderBrush = GetRenderBrush(hashcode);
  18. var geometryGroup = new GeometryGroup();
  19. void AddRec(int i, int j, bool hidden = false)
  20. {
  21. var rec = new RectangleGeometry(new Rect(new Point(i, j), hidden ? new Size() : new Size(1, 1)));
  22. geometryGroup.Children.Add(rec);
  23. }
  24. var index = 0;
  25. for (var i = 0; i < 2; i++)
  26. {
  27. for (var j = 0; j < 5; j++, index++)
  28. {
  29. AddRec(i, j, renderData[index] == 0);
  30. }
  31. }
  32. for (var j = 0; j < 5; j++, index++)
  33. {
  34. AddRec(2, j, renderData[index] == 0);
  35. }
  36. index -= 10;
  37. for (var i = 3; i < 5; i++)
  38. {
  39. for (var j = 0; j < 5; j++, index++)
  40. {
  41. AddRec(i, j, renderData[index] == 0);
  42. }
  43. index -= 10;
  44. }
  45. var path = new Path
  46. {
  47. Data = geometryGroup,
  48. Fill = renderBrush,
  49. VerticalAlignment = VerticalAlignment.Top,
  50. Stretch = Stretch.Uniform
  51. };
  52. RenderOptions.SetEdgeMode(path, EdgeMode.Aliased);
  53. return path;
  54. }
  55. private string GetHashCode(string id)
  56. {
  57. var md5 = MD5.Create();
  58. var bytes = Encoding.ASCII.GetBytes(id);
  59. var hash = md5.ComputeHash(bytes);
  60. var stringBuilder = new StringBuilder();
  61. foreach (var item in hash)
  62. {
  63. stringBuilder.Append(item.ToString("X2"));
  64. }
  65. return stringBuilder.ToString();
  66. }
  67. private int[] GetRenderData(string hashcode)
  68. {
  69. var arr = new int[RenderDataMaxLength];
  70. for (var i = 0; i < RenderDataMaxLength; i++)
  71. {
  72. var c = hashcode[i];
  73. var v = (int) c;
  74. arr[i] = v % 2;
  75. }
  76. return arr;
  77. }
  78. private Brush GetRenderBrush(string hashcode)
  79. {
  80. var v = (double) int.Parse(hashcode.Substring(hashcode.Length - 7), NumberStyles.HexNumber);
  81. var scale = v / 0xfffffff;
  82. var color = Hsl2Rgb(scale);
  83. return new SolidColorBrush(color);
  84. }
  85. //adapted from https://github.com/stewartlord/identicon.js/blob/4fad7cafec1b7a4d896015e084e861625ef5d64f/identicon.js#L110
  86. private Color Hsl2Rgb(double h, double s = 0.7, double b = 0.5)
  87. {
  88. h *= 6;
  89. var arr = new[]
  90. {
  91. b += s *= b < .5 ? b : 1 - b,
  92. b - h % 1 * s * 2,
  93. b -= s *= 2,
  94. b,
  95. b + h % 1 * s,
  96. b + s
  97. };
  98. var hValue = (int) Math.Floor(h);
  99. return Color.FromRgb((byte) (arr[hValue % 6] * 255), (byte) (arr[(hValue | 16) % 6] * 255),
  100. (byte) (arr[(hValue | 8) % 6] * 255));
  101. }
  102. }