2010-06-15 46 views
6

我編寫了一個小工具類,將BitmapSource對象保存爲圖像文件。圖像文件可以是bmp,jpeg或png。下面是代碼:爲什麼在保存BitmapSource到WPF中的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是唯一的格式,可以生成我所看到的精確複製品,如果我使用WPF Image控件在屏幕上顯示BitmapSource

下面是結果:


BMP - 太暗

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


JPEG - 過於飽和

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


PNG - 正確

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


爲什麼會出現不同的文件類型完全不同的結果?

我應該注意到,在我的例子中BitmapSource使用的是0.1的alpha值(這就是爲什麼它看起來非常不飽和),但應該可以以任何圖像格式顯示結果顏色。我知道如果我使用類似HyperSnap的屏幕截圖,無論我保存什麼文件類型,它都會顯示正確。


這裏是保存爲bmp一個的HyperSnap屏幕捕捉:

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

正如你所看到的,這是沒有問題的,所以肯定有一些奇怪的WPF的圖像編碼器。

我的設置有誤嗎?我錯過了什麼嗎?

+0

你在內存中繪製這些圖像,然後將它們保存?還是來自磁盤加載的映像? – 2010-06-15 01:21:38

+0

@Adam,這些圖像是使用'RenderTargetBitmap.Render(UIElement)'從內存中(和屏幕上)'Viewport3D'捕獲的。 – devuxer 2010-06-15 01:29:00

回答

7

我個人認爲看到你所看到的並不令人吃驚。 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"); 

無論是System.Drawing還是WPF編碼器,PNG格式都可以正常工作。 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)); 

我的形象有一個背景顏色,所以不支持Alpha通道編碼器可以確定輸出顏色應該是每個像素的內容。現在我所有的圖片都看起來正確

對於您的情況,您應該將RenderTargetBitmap指定爲背景顏色的控件,或者在渲染圖像時繪製背景顏色。如果您的第三方打印屏幕工作的原因是最終透明顏色在那一點(在具有背景顏色的窗口上)具有背景色。但在WPF中,你正在處理沒有一個集合的元素;在元素上使用RTB不會繼承其各種父元素的屬性,如背景顏色。

+0

+1。謝謝,亞當!沒有背景會讓事情變得很糟糕,這很有意義。有趣的是,如果您查看從HyperSnap保存的bmp,​​它具有非常淺的藍色背景。用PNG,它是完全透明的。 – devuxer 2010-06-15 04:20:57

+0

它是淺藍色背景還是部分透明的藍色背景?你確定背景是在你正在RTB的元素(或孩子)?如果它高一級,則不算。 – 2010-06-15 13:48:24

相關問題