Search code examples
c#wpficonstransparency

Create Icon with transparent background from Control Visual


I'm using HardCodet.NotifyIcon.Wpf to display a status icon in the system tray. I need to have the icon change so I can't use a resource file for the icon. I have a usercontrol that I draw in my app an want to use the visual from that control as the source for my tray icon. I have everything working except that the icon on the tray has a black background instead of transparent. If I draw a rectangle that color shows up. I tried setting the rectangle color to transparent but the result was black. The closest I've gotten with a workaround is trying to draw the background to match the taskbar color. I couldn't find a way to get the taskbar color, and the window title color is a bit lighter (used in the sample code below). Here is the code I've gotten so far using snippets from various searches.

//can't figure out how to render the MsgNotifyIcon visual as an icon with a tranparent background.

RenderTargetBitmap rtb = new RenderTargetBitmap((int)MsgNotifyIcon.ActualWidth, (int)MsgNotifyIcon.ActualHeight, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(MsgNotifyIcon);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
var rect = new Rect(0, 0, MsgNotifyIcon.RenderSize.Width, MsgNotifyIcon.RenderSize.Height);

int argbColor = (int)Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", null);
var color = System.Drawing.Color.FromArgb(argbColor);
Color taskbarcolor = System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B);

using (drawingContext)
{
    drawingContext.PushTransform(new ScaleTransform(1, 1));

    drawingContext.DrawRectangle(new SolidColorBrush(taskbarcolor), null, rect);
    drawingContext.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0), new System.Windows.Point(MsgNotifyIcon.ActualWidth, MsgNotifyIcon.ActualHeight)));
}
rtb.Render(drawingVisual);

BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
MemoryStream stream = new MemoryStream();
encoder.Save(stream);
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(stream);
MsgNotifyTBIcon.Icon = System.Drawing.Icon.FromHandle(bmp.GetHicon()) ;
MsgNotifyTBIcon.Visibility = Visibility.Visible;

Is there a way to accomplish this?

This similar question didn't have any answers that worked in my situation.


Solution

  • BmpBitmapEncoder does not support transparency. Use a PngBitmapEncoder instead:

    var encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(rtb));
    ...