0

I'm loading a BitmapImage from a BitmapSource and i always find the BitmapImage's format is Bgr32 instead of Bgra32 which the BitmapSource is. There is a similar thread on this here: BitmapImage from file PixelFormat is always bgr32

but using BitmapCreateOptions.PreservePixelFormat didn't work for me as was suggested in the thread. here's what i'm doing:

// I have verified that b is a valid BitmapSource and its format is Bgra32
// the following code produces a file (testbmp2.bmp) with an alpha channel as expected
// placing a breakpoint here and querying b.Format in the Immediate window also produces
// a format of Bgra32
BmpBitmapEncoder test = new BmpBitmapEncoder();
FileStream stest = new FileStream(@"c:\temp\testbmp2.bmp", FileMode.Create);
test.Frames.Add(BitmapFrame.Create(b));
test.Save(stest); 
stest.Close();

// however, this following snippet results in bmp.Format being Bgr32
BitmapImage bmp = new BitmapImage();
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
MemoryStream stream = new MemoryStream();

encoder.Frames.Add(BitmapFrame.Create(b));
encoder.Save(stream);

bmp.BeginInit();
bmp.StreamSource = new MemoryStream(stream.ToArray());
bmp.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
bmp.CacheOption = BitmapCacheOption.None;
bmp.EndInit();

stream.Close();

Is there a way to create a BitmapImage from the BitmapSource and preserver the alpha channel?

Update: I used the same code posted in the the other thread to load testbmp2.bmp from file and after loading, the Format property is Bgr32.

BitmapImage b1 = new BitmapImage();
b1.BeginInit();
b1.UriSource = new Uri(@"c:\temp\testbmp2.bmp");
b1.CreateOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreImageCache;
b1.CacheOption = BitmapCacheOption.OnLoad;
b1.EndInit();

so maybe i'm not saving the FileStream/MemoryStream correctly? That doesn't seem right since after saving the FileStream, I can open testbmp2.bmp in Photoshop and see the alpha channel.

Update 2: I think I need to re-word the issue I'm having. I'm trying to display separate channels of a texture. I am displaying the bitmap via an Image control. I have a simple HLSL pre compiled shader assigned to the Image's Effect property that will mask out the channels based user input. Not being able to get the BitmapSource into a BitmapImage while retaining the alpha channel was only part of the problem. I realize now that since my original BitmapSource's Format was Bgra32 I could assign that directly to the Image's Source property. The problem appears to be that an Image object will only display texels with pre-multiplied alpha...? Here's my shader code:

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; // * 0.5 + 0.5;
        outCol.g = outCol.a;
        outCol.b = outCol.a;
    }

    outCol.a = 1;

    return outCol;
}

I've tested it pretty extensively and I'm pretty sure that its setting the outCol value properly. When i pass in a channel mask value of (1.0, 1.0, 1.0, 0.0) the image displayed is the RGB channels with the areas of the alpha that are black drawing as black - as you would expect if WPF was pre-multiplying the alpha on to the RGB channels. Does anyone know of any way to dispaly a BitmapSource in an Image without pre multiplied alpha? Or more to the point, is there a way to have the effect receive the texture before the alpha pre-multiply happens? I'm not sure what order things are done in, but apparently the pre-multiply happens before the texture is written to the s0 register and the shader gets to work on it. I could try to do this with WriteableBitmap and copying the alpha out to another BitmapSource but that would all be using software rendering i think...?

Community
  • 1
  • 1
user1200340
  • 157
  • 1
  • 3
  • 10
  • Sorry for the newb question, but anyone know how to close this post? Or should I just delete it? I've opened a new post with the question about pre-multiplied alpha and since my BitmapSource is Bgra32 and can be set directly as an Image object's Source, this post is no longer valid. thanks! – user1200340 Jul 02 '13 at 17:18

1 Answers1

0

I ran into a similar problem lately. The BmpBitmapEncoder does not care about the alpha channel and therefore does not preserve it. An easy fix is to use a PngBitmapEncoder instead.

douche_satan
  • 179
  • 2
  • 7