【问题标题】:BitmapImage from BitmapSource always Bgr32来自 BitmapSource 的 BitmapImage 始终为 Bgr32
【发布时间】:2013-11-29 02:47:54
【问题描述】:

我正在从 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: 我想我需要重新措辞我遇到的问题。我正在尝试显示纹理的单独通道。我通过图像控件显示位图。我有一个简单的 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 寄存器并且着色器开始处理它之前。我可以尝试使用 WriteableBitmap 来执行此操作并将 alpha 复制到另一个 BitmapSource 但我认为这都将使用软件渲染...?

【问题讨论】:

  • 抱歉这个新手问题,但有人知道如何关闭这篇文章吗?还是我应该删除它?我打开了一篇关于预乘 alpha 的新帖子,并且由于我的 BitmapSource 是 Bgra32 并且可以直接设置为 Image 对象的 Source,因此该帖子不再有效。谢谢!

标签: wpf alpha bitmapimage bitmapsource pixelformat


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多