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, я мог назначить его непосредственно свойству Image 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, но все это будет использовать программный рендеринг, я думаю ...?


person user1200340    schedule 02.07.2013    source источник
comment
Извините за вопрос newb, но кто-нибудь знает, как закрыть этот пост? Или надо просто удалить? Я открыл новый пост с вопросом о предварительно умноженном альфа-канале, и поскольку мой BitmapSource - это Bgra32 и может быть установлен напрямую как источник объекта изображения, этот пост больше не действителен. Благодарность!   -  person user1200340    schedule 02.07.2013


Ответы (1)


Недавно я столкнулся с подобной проблемой. BmpBitmapEncoder не заботится об альфа-канале и, следовательно, не сохраняет его. Простое решение - использовать вместо этого PngBitmapEncoder.

person douche_satan    schedule 27.09.2013