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...?