代码之家  ›  专栏  ›  技术社区  ›  devuxer

为什么在WPF中将位图源保存为bmp、jpeg和png时会得到完全不同的结果

  •  6
  • devuxer  · 技术社区  · 14 年前

    我写了一个小实用类 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 位图源 Image 控制。

    结果如下:


    骨形态发生蛋白 太暗了

    too dark http://img822.imageshack.us/img822/7403/terrainbmp.png


    JPEG格式 - 太饱和了

    too saturated http://img816.imageshack.us/img816/8127/terrainjpeg.jpg


    - 对的

    correct http://img810.imageshack.us/img810/6243/terrainpng.png


    我应该注意到 位图源 在我的示例中,使用alpha值0.1(这就是为什么它看起来非常不饱和),但是应该可以以任何图像格式显示结果颜色。我知道,如果我使用类似HyperSnap的东西进行屏幕截图,不管我保存到什么文件类型,它看起来都是正确的。


    以下是保存为bmp的HyperSnap屏幕截图:

    correct http://img815.imageshack.us/img815/9966/terrainbmphypersnap.png

    我的设置错了吗?我错过什么了吗?

    1 回复  |  直到 14 年前
        1
  •  7
  •   Adam Sills    14 年前

    我个人认为看到你所看到的并不奇怪。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编码器不工作。它们显示一个纯蓝色的矩形。

    这里的关键是我没有在我的图像中指定背景色。如果没有背景色,图像将无法以不支持alpha通道(BMP/JPG)的格式正确渲染。加上一行代码:

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

    在您的情况下,您应该使用指定的背景色渲染目标位图控件,或者在渲染图像时绘制背景色。