BitmapImage из BitmapSource всегда Bgr32
Я загружаю BitmapImage из BitmapSource и всегда нахожу, что формат BitmapImage - это Bgr32 вместо Bgra32, которым является BitmapSource. Здесь есть похожая тема: BitmapImage из файла PixelFormat всегда 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();
Есть ли способ создать BitmapImage из BitmapSource и сохранить альфа-канал?
Обновление: я использовал тот же код, опубликованный в другом потоке, чтобы загрузить 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 я могу открыть testbmp2.bmp в Photoshop и посмотреть альфа-канал.
Обновление 2: я думаю, что мне нужно перефразировать проблему, которая у меня возникла. Я пытаюсь отобразить отдельные каналы текстуры. Я отображаю растровое изображение через элемент управления изображением. У меня есть простой скомпилированный шейдер HLSL, назначенный свойству Image's Effect, который будет маскировать вводимые пользователем каналы. Невозможность получить BitmapSource в BitmapImage при сохранении альфа-канала была только частью проблемы. Теперь я понимаю, что, поскольку моим исходным форматом BitmapSource был Bgra32, я мог назначить его непосредственно в свойстве Source изображения. Проблема заключается в том, что объект Image будет отображать только тексели с предварительно умноженным альфа-каналом...? Вот мой код шейдера:
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 с областями альфа, которые черным цветом обозначены черным - как и следовало ожидать, если бы WPF предварительно умножал альфа на каналах RGB. Кто-нибудь знает какой-либо способ отображения BitmapSource в изображении без предварительного умножения альфа? Или, более конкретно, есть ли способ получить эффект, чтобы получить текстуру до того, как произойдет предварительное умножение альфа? Я не уверен, в каком порядке все делается, но, видимо, предварительное умножение происходит до того, как текстура записывается в регистр s0, и шейдер начинает работать с ней. Я мог бы попытаться сделать это с помощью WriteableBitmap и скопировать альфа-канал на другой BitmapSource, но это все будет с использованием программного рендеринга, я думаю...?
1 ответ
Я столкнулся с подобной проблемой в последнее время. BmpBitmapEncoder не заботится об альфа-канале и поэтому не сохраняет его. Легкое решение - использовать вместо него PngBitmapEncoder.