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.

Другие вопросы по тегам