0

我正在从 BitmapSource 加载 BitmapImage,我总是发现 BitmapImage 的格式是 Bgr32 而不是 BitmapSource 的 Bgra32。这里有一个类似的线程: BitmapImage from file PixelFormat always is 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: 我认为我需要重新表述我遇到的问题。我正在尝试显示纹理的单独通道。我通过图像控件显示位图。我有一个简单的 HLSL 预编译着色器分配给图像的效果属性,它将屏蔽基于通道的用户输入。在保留 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 寄存器并且着色器开始处理它之前。

4

1 回答 1

0

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

于 2013-09-27T21:57:24.410 回答