114 lines
3.9 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|