Files
HandyControl/src/Shared/HandyControl_Shared/Data/GlowWindow/GlowBitmap.cs
T
2020-01-18 14:23:47 +08:00

114 lines
3.9 KiB
C#

using System;
using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using HandyControl.Tools.Interop;
namespace HandyControl.Data
{
internal class GlowBitmap : DisposableObject
{
internal const int GlowBitmapPartCount = 16;
private const int BytesPerPixelBgra32 = 4;
private static readonly CachedBitmapInfo[] _transparencyMasks = new CachedBitmapInfo[GlowBitmapPartCount];
private readonly InteropValues.BITMAPINFO _bitmapInfo;
private readonly IntPtr _pbits;
internal GlowBitmap(IntPtr hdcScreen, int width, int height)
{
_bitmapInfo.biSize = Marshal.SizeOf(typeof(InteropValues.BITMAPINFOHEADER));
_bitmapInfo.biPlanes = 1;
_bitmapInfo.biBitCount = 32;
_bitmapInfo.biCompression = 0;
_bitmapInfo.biXPelsPerMeter = 0;
_bitmapInfo.biYPelsPerMeter = 0;
_bitmapInfo.biWidth = width;
_bitmapInfo.biHeight = -height;
Handle = InteropMethods.CreateDIBSection(
hdcScreen,
ref _bitmapInfo,
0u,
out _pbits,
IntPtr.Zero,
0u);
}
internal IntPtr Handle { get; }
internal IntPtr DIBits => _pbits;
internal int Width => _bitmapInfo.biWidth;
internal int Height => -_bitmapInfo.biHeight;
protected override void DisposeNativeResources() => InteropMethods.DeleteObject(Handle);
private static byte PremultiplyAlpha(byte channel, byte alpha) => (byte)(channel * alpha / 255.0);
internal static GlowBitmap Create(GlowDrawingContext drawingContext, GlowBitmapPart bitmapPart, Color color)
{
var orCreateAlphaMask =
GetOrCreateAlphaMask(bitmapPart);
var glowBitmap =
new GlowBitmap(
drawingContext.ScreenDC,
orCreateAlphaMask.Width,
orCreateAlphaMask.Height);
for (var i = 0; i < orCreateAlphaMask.DIBits.Length; i += BytesPerPixelBgra32)
{
var b = orCreateAlphaMask.DIBits[i + 3];
var val = PremultiplyAlpha(color.R, b);
var val2 = PremultiplyAlpha(color.G, b);
var val3 = PremultiplyAlpha(color.B, b);
Marshal.WriteByte(glowBitmap.DIBits, i, val3);
Marshal.WriteByte(glowBitmap.DIBits, i + 1, val2);
Marshal.WriteByte(glowBitmap.DIBits, i + 2, val);
Marshal.WriteByte(glowBitmap.DIBits, i + 3, b);
}
return glowBitmap;
}
private static CachedBitmapInfo GetOrCreateAlphaMask(GlowBitmapPart bitmapPart)
{
if (_transparencyMasks[(int)bitmapPart] == null)
{
var bitmapImage = new BitmapImage(new Uri($"pack://application:,,,/HandyControl;Component/Resources/Images/GlowWindow/{bitmapPart}.png"));
var array = new byte[BytesPerPixelBgra32 * bitmapImage.PixelWidth * bitmapImage.PixelHeight];
var stride = BytesPerPixelBgra32 * bitmapImage.PixelWidth;
bitmapImage.CopyPixels(array, stride, 0);
_transparencyMasks[(int)bitmapPart] =
new CachedBitmapInfo(
array,
bitmapImage.PixelWidth,
bitmapImage.PixelHeight);
}
return _transparencyMasks[(int)bitmapPart];
}
private sealed class CachedBitmapInfo
{
internal readonly byte[] DIBits;
internal readonly int Height;
internal readonly int Width;
internal CachedBitmapInfo(byte[] diBits, int width, int height)
{
Width = width;
Height = height;
DIBits = diBits;
}
}
}
}