Search code examples
c#wpfxaml

FormatConvertedBitmap with alpha


I've a problem in WPF. I'm making a delete button with an image in it. When the button is disabled, however, I wanted to display a greyscale image.

I found the Thomas Lebrun implementation, but I don't want to add the whole class in my program. Instead I tried to mimic the behavior in this way:

BitmapImage img_Delete = new System.Windows.Media.Imaging.BitmapImage(new Uri("the png URI", UriKind.RelativeOrAbsolute));
ImageSource img_DeleteDisabled = null;

[...]
Button btDel = new Button() { Width = 20, Height = 20, ToolTip = "Delete", Margin = new Thickness(5), HorizontalAlignment = System.Windows.HorizontalAlignment.Right };
btDel.IsEnabled = isdeletable(obj);

if (!btDel.IsEnabled && (img_DeleteDisabled == null))
{
    img_DeleteDisabled = new FormatConvertedBitmap(img_Delete, PixelFormats.Gray32Float, null, 0);
}

btDel.Content = (new System.Windows.Controls.Image()
{
    Width = 16,
    Height = 16,
    HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
    VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
    Source = btDel.IsEnabled ? img_Delete : img_DeleteDisabled
});

It behaves in the expected way, except.. Well, I'll show you:

Enabled and disabled

The left one is enabled, the right one is disabled

As you can see the alpha channel is gone. How can I integrate it back?


Solution

  • Helped by the comments, I figured out I was thinking about the wrong place where to apply the opacity mask.

    The OpacityMask should be applied to the button, not to the image. This is because the opacity applies to the whole image rather than its source.

    For this reason, the correct way to implement this is

    btDel.Content = (new System.Windows.Controls.Image()
    {
        Width = 16,
        Height = 16,
        HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
        VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
        Source = btDel.IsEnabled ? img_Delete : img_DeleteDisabled,
        OpacityMask = new ImageBrush(img_Delete)
    });
    

    This way the mask is applied to the button image. The result is what I needed:

    Enabled and disabled