来自BitmapSource的BitmapImage总是Bgr32

时间:2013-07-02 00:20:59

标签: wpf alpha bitmapimage bitmapsource pixelformat

我正在从BitmapSource加载BitmapImage,我总是发现BitmapImage的格式是Bgr32而不是BitmapSource的Bgra32。这里有一个类似的线程: BitmapImage from file PixelFormat is always bgr32

但是使用BitmapCreateOptions.PreservePixelFormat并不像我在线程中所建议的那样对我有用。这就是我正在做的事情:

// 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();

<击> 有没有办法从BitmapSource创建一个BitmapImage并保留alpha通道?

更新 我使用在另一个线程中发布的相同代码从文件加载testbmp2.bmp,加载后,Format属性为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();

所以也许我没有正确保存FileStream / MemoryStream?这似乎不对,因为在保存FileStream后,我可以在Photoshop中打开testbmp2.bmp并查看alpha通道。

更新2: 我想我需要重新说出我所拥有的问题。我正在尝试显示纹理的单独通道。我通过Image控件显示位图。我有一个简单的HLSL预编译着色器分配给Image的Effect属性,它将屏蔽基于用户输入的通道。在保留alpha通道的同时无法将BitmapSource放入BitmapImage只是问题的一部分。我现在意识到,由于我原来的BitmapSource的格式是Bgra32,我可以将它直接分配给Image的Source属性。问题似乎是Image对象只显示带有预乘alpha的纹素...?这是我的着色器代码:

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;
}

我已经对它进行了相当广泛的测试,我很确定它正确地设置了outCol值。当我传入一个(1.0,1.0,1.0,0.0)的通道掩码值时,显示的图像是RGB通道,其中黑色的alpha区域绘制为黑色 - 正如您所预期的那样,如果WPF预先乘以alpha在RGB通道上。有没有人知道在没有预先乘法alpha的情况下显示图像中的BitmapSource的任何方法?或者更重要的是,有没有办法让这个效果在alpha预乘之前接收纹理?我不确定是做了什么命令,但显然在将纹理写入s0寄存器并且着色器开始工作之前发生了预乘。我可以尝试用WriteableBitmap执行此操作并将alpha复制到另一个BitmapSource但是我认为这些都会使用软件渲染......?

1 个答案:

答案 0 :(得分:0)

我最近遇到了类似的问题。 BmpBitmapEncoder不关心alpha通道,因此不保留它。一个简单的解决方法是使用PngBitmapEncoder。