Я записал немного служебного класса, который сохраняет 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.
У меня есть установка неправильно? Я пропускаю что-то?
Лично я не считаю слишком удивительным то, что вы видите. 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 на элементе не наследует свойства его различных родительских элементов, таких как цвет фона.