1

I'm trying to display the separate R, G, B and A channels of a texture based on user input. I'm using an Image class to display textures that have alpha channels. These textures are loaded in to BitmapSource objects and have a Format of Bgra32. The problem is that when I set the Image's Source to the BitmapSource, if I display any combination of the R, G or B channels, I always get pixels that are pre-multiplied by the alpha value. I wrote a really simple shader, pre-compiled it, and used a ShaderEffect class to assign to the Image's Effect property in order to separate and display the separate channels, but apparently, the shader is given the texture after WPF has pre-multiplied the alpha value onto the texture.

Here's the code snippet for setting the Image's Source:

BitmapSource b = MyClass.GetBitmapSource(filepath);

// just as a test, write out the bitmap to file to see if there's an alpha.
// see attached image1
BmpBitmapEncoder test = new BmpBitmapEncoder();
//test.Compression = TiffCompressOption.None;
FileStream stest = new FileStream(@"c:\temp\testbmp2.bmp", FileMode.Create);
test.Frames.Add(BitmapFrame.Create(b));
test.Save(stest);
stest.Close();

// effect is a class derived from ShaderEffect. The pixel shader associated with the
// effect displays the color channel of the texture loaded in the Image object
// depending on which member of the Point4D is set. In this case, we are showing
// the RGB channels but no alpha
effect.PixelMask = new System.Windows.Media.Media3D.Point4D(1.0f, 1.0f, 1.0f, 0.0f);

this.image1.Effect = effect;
this.image1.Source = b;
this.image1.UpdateLayout();

Here's the shader code (its pretty simple, but I figured I'd include it just for completeness):

sampler2D  inputImage : register(s0);
float4 channelMasks : register(c0);

float4 main (float2 uv : TEXCOORD) : COLOR0
{
    float4 outCol = tex2D(inputImage, uv);  

    if (!any(channelMasks.rgb - float3(1, 0, 0)))
    {
        outCol.rgb = float3(outCol.r, outCol.r, outCol.r);
    }
    else if (!any(channelMasks.rgb - float3(0, 1, 0)))
    {
        outCol.rgb = float3(outCol.g, outCol.g, outCol.g);
    }
    else if (!any(channelMasks.rgb - float3(0, 0, 1)))
    {
        outCol.rgb = float3(outCol.b, outCol.b, outCol.b);
    }
    else
    {
        outCol *= channelMasks; 
    }

    if (channelMasks.a == 1.0)
    {
        outCol.r = outCol.a;
        outCol.g = outCol.a;
        outCol.b = outCol.a;
    }

    outCol.a = 1;

    return outCol;
}

Here's the output from the code above:
(sorry, i don't have enough reputation points to post images or apparently more than 2 links)

The file save to disk (C:\temp\testbmp2.bmp) in photoshop:
http://screencast.com/t/eeEr5kGgPukz

Image as displayed in my WPF application (using image mask in code snippet above):
http://screencast.com/t/zkK0U5I7P7

Abe Heidebrecht
  • 30,090
  • 7
  • 62
  • 66
user1200340
  • 157
  • 1
  • 3
  • 10
  • Two more images that I couldn't put in the original post: Image from WPF app using image mask (0.0, 0.0, 0.0, 1.0) - alpha only: http://screencast.com/t/py4tuYB6Zf Image from WPf app using image mask (1.0, 0.0, 0.0, 0.0) - red channel only: http://screencast.com/t/JW4JJbYbpr – user1200340 Jul 02 '13 at 17:11
  • I can't view your images at work (dumb firewall). But, for other people to be able to help you, you're probably going to need to post the code for `MyClass.GetBitmapSource()`. – Abe Heidebrecht Jul 02 '13 at 18:49
  • @Abe - I can't post GetBitmapSource()..its a ton of code and embedded in some proprietary stuff. Again, saving the BitmapSource returned by that call definitely yields a .bmp file with R,G,B and A channels in photoshop. In any case, I found a solution, but I'm not sure how optimal is it (or isn't). The issue is that WPF always pre-multiplies the alpha for perf reasons. So what I did was use a WriteableBitmap to copy the alpha channel out of the original BitmapSource and pass that to my shader as a second tex2D. I then compsite them together based on the user supplied channel masks. – user1200340 Jul 02 '13 at 22:45

0 Answers0