Почему я получаю совершенно другие результаты при сохранении BitmapSource к bmp, jpeg, и png в WPF

Я записал немного служебного класса, который сохраняет BitmapSource объекты к файлам изображений. Файлы изображений могут быть или bmp, jpeg, или png. Вот код:

public class BitmapProcessor
{
    public void SaveAsBmp(BitmapSource bitmapSource, string path)
    {
        Save(bitmapSource, path, new BmpBitmapEncoder());
    }

    public void SaveAsJpg(BitmapSource bitmapSource, string path)
    {
        Save(bitmapSource, path, new JpegBitmapEncoder());
    }

    public void SaveAsPng(BitmapSource bitmapSource, string path)
    {
        Save(bitmapSource, path, new PngBitmapEncoder());
    }

    private void Save(BitmapSource bitmapSource, string path, BitmapEncoder encoder)
    {
        using (var stream = new FileStream(path, FileMode.Create))
        {
            encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
            encoder.Save(stream);
        }
    }
}

Каждый из трех Save работа методов, но я получаю неожиданные результаты с bmp и jpeg. Png является единственным форматом, который производит точное воспроизведение того, что я вижу, показываю ли я BitmapSource на экране с помощью WPF Image управление.

Вот результаты:


BMP - слишком темный

слишком темный http://img822.imageshack.us/img822/7403/terrainbmp.png


JPEG - слишком влажный

слишком влажный http://img816.imageshack.us/img816/8127/terrainjpeg.jpg


PNG - корректный

корректный http://img810.imageshack.us/img810/6243/terrainpng.png


Почему я получаю совершенно другие результаты для различных типов файлов?

Я должен отметить что BitmapSource в моем использовании в качестве примера альфа-значение 0,1 (который является, почему это появляется очень desaturated), но должно быть возможно показать итоговые цвета в любом формате изображения. Я знаю, получаю ли я снимок экрана с помощью чего-то как HyperSnap, это будет выглядеть корректным независимо от того, к какому типу файла я сохраняю.


Вот снимок экрана HyperSnap, сохраненный как bmp:

корректный http://img815.imageshack.us/img815/9966/terrainbmphypersnap.png

Как Вы видите, это не проблема, таким образом, существует определенно что-то странное о кодерах изображения WPF.

У меня есть установка неправильно? Я пропускаю что-то?

6
задан devuxer 15 June 2010 в 01:09
поделиться

1 ответ

Лично я не считаю слишком удивительным то, что вы видите. BMP и JPG не поддерживают непрозрачность, а PNG поддерживает.

Возьмите этот код, который создает частично прозрачный синий прямоугольник на изображении.

WriteableBitmap bm = new WriteableBitmap( 100, 100, 96, 96, PixelFormats.Pbgra32, null );
bm.Lock();

Bitmap bmp = new Bitmap( bm.PixelWidth, bm.PixelHeight, bm.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format32bppArgb, bm.BackBuffer );
using( Graphics g = Graphics.FromImage( bmp ) ) {
    var color = System.Drawing.Color.FromArgb( 20, System.Drawing.Color.Blue);
    g.FillRectangle(
        new System.Drawing.SolidBrush( color ),
        new RectangleF( 0, 0, bmp.Width, bmp.Height ) );
}

bmp.Save( @".\000_foo.bmp", System.Drawing.Imaging.ImageFormat.Bmp );
bmp.Save( @".\000_foo.jpg", System.Drawing.Imaging.ImageFormat.Jpeg );
bmp.Save( @".\000_foo.png", System.Drawing.Imaging.ImageFormat.Png );

bmp.Dispose();

bm.AddDirtyRect( new Int32Rect( 0, 0, bm.PixelWidth, bm.PixelHeight ) );
bm.Unlock();

new BitmapProcessor().SaveAsBmp( bm, @".\foo.bmp" );
new BitmapProcessor().SaveAsJpg( bm, @".\foo.jpg" );
new BitmapProcessor().SaveAsPng( bm, @".\foo.png" );

Форматы PNG всегда работают, будь то System.Drawing или кодировщики WPF. Кодировщики JPG и BMP не работают. Они показывают сплошной синий прямоугольник.

Ключевым моментом здесь является то, что я не указал цвет фона в своем изображении. Без цвета фона изображение не будет правильно отображаться в форматах, не поддерживающих альфа-канал (BMP/JPG). С помощью одной дополнительной строки кода:

g.Clear( System.Drawing.Color.White );
g.FillRectangle(
    new System.Drawing.SolidBrush( color ),
    new RectangleF( 0, 0, bmp.Width, bmp.Height ) );

Мое изображение имеет цвет фона, поэтому кодеры, не поддерживающие альфа-канал, могут определить, какой цвет должен быть на пикселе. Теперь все мои изображения выглядят правильно.

В вашем случае вы должны либо RenderTargetBitmap элемент управления с заданным цветом фона, либо рисовать цвет фона при рендеринге изображения.

И, к вашему сведению, причина, по которой ваш сторонний экран печати работает, заключается в том, что в конечном итоге прозрачные цвета имеют цвет фона в этой точке (находясь в окне, которое имеет цвет фона). Но внутри WPF вы имеете дело с элементами, которые не имеют такого набора; использование RTB на элементе не наследует свойства его различных родительских элементов, таких как цвет фона.

7
ответ дан 17 December 2019 в 00:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: