bokibeg
bokibeg

Reputation: 2142

Making bitmaps with magenta background appear transparent in WPF

I'm in process of converting some legacy software that is 15 years old into WPF and its graphics are often some 8-bit bitmaps with magenta background, something like this:

Transparency test

With Gdi32 it was common approach to use magenta as transparency key to draw graphics. With System.Drawing it would be a one liner, i.e. _myImg.MakeTransparent(Color.Magenta). But what about WPF? Is there even such a thing as standard practice for aforementioned scenario?

I was really hoping this would work out of the box:

    <Image Width="128">
        <Image.Source>
            <BitmapImage UriSource="Media\opacityTest.bmp" />
        </Image.Source>
        <Image.OpacityMask>
            <SolidColorBrush Color="Magenta" />
        </Image.OpacityMask>
    </Image>

Alas, although it is allowed, it does nothing:

The result

Am I missing something or is this impossible in WPF?

Ultimately, I may have to write code to convert these bitmaps into transparent pngs, cache them somewhere and load those instead. If so, does anyone know of any resources that can help me accomplish this aside from Gdi+?

There is a similar question: Make part of an image transparent. But no definitive answer (or I really can't quite believe it's not possible).

Upvotes: 1

Views: 1993

Answers (1)

bokibeg
bokibeg

Reputation: 2142

I ended up creating a new image (32bit pargb) based on the original image and a color key, here's the code for whatever it's worth:

BitmapSource MakeTransparent(BitmapSource img, Color maskColor)
{           
    var format = PixelFormats.Pbgra32;
    var stride = ((img.PixelWidth * format.BitsPerPixel + 31) & ~31) >> 3;
    var pixels = new byte[img.PixelHeight * stride];

    img.CopyPixels(pixels, stride, 0);

    for (var i = 0; i < stride * img.PixelHeight; i += 4)
        if (Color.FromRgb(pixels[i + 2], pixels[i + 1], pixels[i]) == maskColor)
            for (var j = i; j < i + 4; j++)
                pixels[j] = 0;

    return BitmapSource.Create(
        img.PixelWidth, img.PixelHeight,
        img.DpiX, img.DpiY,
        format,
        null,
        pixels,
        stride);
}

It does not use System.Drawing so no Gdi+ required, it simply modifies the pixel array replacing the specified maskColor with premultiplied alpha rgb values set to 0.

Example usage: TestImage = MakeTransparent(new BitmapImage(new Uri(@"opacityTest.bmp", UriKind.Relative)), Colors.Magenta);

The result:

enter image description here

Upvotes: 2

Related Questions