GlowBitmap.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Windows.Media;
  4. using System.Windows.Media.Imaging;
  5. using HandyControl.Tools.Interop;
  6. namespace HandyControl.Data;
  7. internal class GlowBitmap : DisposableObject
  8. {
  9. internal const int GlowBitmapPartCount = 16;
  10. private const int BytesPerPixelBgra32 = 4;
  11. private static readonly CachedBitmapInfo[] _transparencyMasks = new CachedBitmapInfo[GlowBitmapPartCount];
  12. private readonly InteropValues.BITMAPINFO _bitmapInfo;
  13. private readonly IntPtr _pbits;
  14. internal GlowBitmap(IntPtr hdcScreen, int width, int height)
  15. {
  16. _bitmapInfo.biSize = Marshal.SizeOf(typeof(InteropValues.BITMAPINFOHEADER));
  17. _bitmapInfo.biPlanes = 1;
  18. _bitmapInfo.biBitCount = 32;
  19. _bitmapInfo.biCompression = 0;
  20. _bitmapInfo.biXPelsPerMeter = 0;
  21. _bitmapInfo.biYPelsPerMeter = 0;
  22. _bitmapInfo.biWidth = width;
  23. _bitmapInfo.biHeight = -height;
  24. Handle = InteropMethods.CreateDIBSection(
  25. hdcScreen,
  26. ref _bitmapInfo,
  27. 0u,
  28. out _pbits,
  29. IntPtr.Zero,
  30. 0u);
  31. }
  32. internal IntPtr Handle { get; }
  33. internal IntPtr DIBits => _pbits;
  34. internal int Width => _bitmapInfo.biWidth;
  35. internal int Height => -_bitmapInfo.biHeight;
  36. protected override void DisposeNativeResources() => InteropMethods.DeleteObject(Handle);
  37. private static byte PremultiplyAlpha(byte channel, byte alpha) => (byte) (channel * alpha / 255.0);
  38. internal static GlowBitmap Create(GlowDrawingContext drawingContext, GlowBitmapPart bitmapPart, Color color)
  39. {
  40. var orCreateAlphaMask =
  41. GetOrCreateAlphaMask(bitmapPart);
  42. var glowBitmap =
  43. new GlowBitmap(
  44. drawingContext.ScreenDC,
  45. orCreateAlphaMask.Width,
  46. orCreateAlphaMask.Height);
  47. for (var i = 0; i < orCreateAlphaMask.DIBits.Length; i += BytesPerPixelBgra32)
  48. {
  49. var b = orCreateAlphaMask.DIBits[i + 3];
  50. var val = PremultiplyAlpha(color.R, b);
  51. var val2 = PremultiplyAlpha(color.G, b);
  52. var val3 = PremultiplyAlpha(color.B, b);
  53. Marshal.WriteByte(glowBitmap.DIBits, i, val3);
  54. Marshal.WriteByte(glowBitmap.DIBits, i + 1, val2);
  55. Marshal.WriteByte(glowBitmap.DIBits, i + 2, val);
  56. Marshal.WriteByte(glowBitmap.DIBits, i + 3, b);
  57. }
  58. return glowBitmap;
  59. }
  60. private static CachedBitmapInfo GetOrCreateAlphaMask(GlowBitmapPart bitmapPart)
  61. {
  62. if (_transparencyMasks[(int) bitmapPart] == null)
  63. {
  64. var bitmapImage = new BitmapImage(new Uri($"pack://application:,,,/HandyControl;Component/Resources/Images/GlowWindow/{bitmapPart}.png"));
  65. var array = new byte[BytesPerPixelBgra32 * bitmapImage.PixelWidth * bitmapImage.PixelHeight];
  66. var stride = BytesPerPixelBgra32 * bitmapImage.PixelWidth;
  67. bitmapImage.CopyPixels(array, stride, 0);
  68. bitmapImage.Freeze();
  69. _transparencyMasks[(int) bitmapPart] =
  70. new CachedBitmapInfo(
  71. array,
  72. bitmapImage.PixelWidth,
  73. bitmapImage.PixelHeight);
  74. }
  75. return _transparencyMasks[(int) bitmapPart];
  76. }
  77. private sealed class CachedBitmapInfo
  78. {
  79. internal readonly byte[] DIBits;
  80. internal readonly int Height;
  81. internal readonly int Width;
  82. internal CachedBitmapInfo(byte[] diBits, int width, int height)
  83. {
  84. Width = width;
  85. Height = height;
  86. DIBits = diBits;
  87. }
  88. }
  89. }