2010-05-10 31 views
12

如何以原始編碼保存圖像?如何以原始格式保存圖像?

看來,保存圖像的唯一方法是使用BitmapEncoder,但我不知道如何從圖像中獲取正確的格式。

實施例:

Clipboard.GetImage()返回一個InteropBitmap這似乎不包含關於原始格式的任何信息。

我也使用擴展方法嘗試:

public static void Save(this BitmapImage image, System.IO.Stream stream) 
{ 
    var decoder = BitmapDecoder.Create(image.StreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); 
    var encoder = BitmapEncoder.Create(decoder.CodecInfo.ContainerFormat); 
    foreach (var frame in decoder.Frames) 
    { 
     encoder.Frames.Add(BitmapFrame.Create(frame)); 
    } 
    encoder.Save(stream); 
} 

但問題是

  1. 所述的ImageSource並不總是一個的BitmapImage(Clipboard.GetImage())例如和
  2. image.StreamSource在某些情況下可能爲空(似乎是通過相對Uri加載圖像時)

有什麼建議嗎?

+0

你能解釋一下你正在經歷的情況嗎?在我看來,如果您要保存圖像,只需將其保存爲所需的格式即可。 BitmapImage似乎是一種格式,原始圖像已被轉換。 – 2010-08-04 22:16:11

回答

19

這裏最根本的問題是「我如何取一個任意的ImageSource並學習它最初編碼的格式?」

答案是,你不能總是這樣做,但對於大多數實際目的來說,有一個解決方法可用。如上面的代碼所示,一旦你瞭解了使用哪種格式,其餘部分都很容易。

你不能總能找出原始格式的原因是,它有可能(用一些非常棘手的代碼!)來子類化BitmapSource來創建一個新的ImageSource,從你喜歡的任何地方獲取它的數據。例如,我可以實現一個返回隨機像素的PseudoRandomBitmapSource。在這種情況下,「原始格式」可能是用於隨機數生成器的種子。

如果你正在處理的內置的ImageSource類之一,找出原來的編碼方式取決於它的確切類,你正在使用:

  1. 對於BitmapImage的,你可以使用的StreamSource或UriSource ,無論哪一個設置。其中任何一個都可以傳遞給BitmapDecoder.Create重載。您的示例代碼顯示瞭如何爲StreamSource執行此操作。這與UriSource完全相同,除非您需要新的Uri(BaseUri, UriSource)並將其傳遞給需要Uri的BitmapDecoder.Create過載。

  2. 對於ColorConvertedBitmap,CroppedBitmap,FormatConvertedBitmap和TransformedBitmap,可以使用公共「Source」屬性獲取底層源代碼,然後使用此算法遞歸檢查其編碼。

  3. 對於CachedBitmap,您只能通過內部字段獲取源位圖。如果您擁有足夠的權限,則可以使用反射訪問,否則您的運氣不佳。

  4. 對於RenderTargetBitmap,WritableBitmap,D3DImage和DrawingImage,由於圖像是從矢量格式或算法「實時」構建的,因此沒有原始編碼。

  5. 對於BitmapFrame,使用Decoder屬性獲取解碼器,然後使用CodecInfo.ContainerFormat。

  6. 對於InteropBitmap或UnmanagedBitmapWrapper,它非常複雜。基本上你需要使用反射來讀取內部的WicSourceHandle屬性,然後調用DangerousGetHandle()來獲得一個實際上是非託管IUnkown的IntPtr。 IWICBitmapDecoder使用非託管代碼,QueryInterface。如果成功,您可以調用IWICBitmapDecoder.GetContainerFormat獲取格式Guid(這仍然是非託管代碼)。如果沒有,關於原始來源的所有信息都已丟失。

正如你所看到的,還有相當,你不能得到源(例如,對於完全解碼位圖的InteropBitmap),或者獲得源需要專門的技術和特權(對於非託管代碼少數情況下InteropBitmap或CachedBitmap內部字段的反射)。

因爲通常很難不可能獲得原始格式,所以尋找保存這些信息的方法是一個好主意,因爲它會傳遞到您的代碼中。如果控制圖像的源,其可以是作爲創建ImageSourceAndFormat類如簡單:

public class BitmapSourceAndFormat 
{ 
    public ImageSource Source { get; set; } 
    public Guid OriginalFormat { get; set; } 
} 

此,如果要放置在圖像上剪貼板是特別有用的。通常,除了將圖像添加到DataObject之外,您還可以添加一個BitmapSourceAndFormat對象。如果這樣做,則粘貼操作將接收包含這兩種格式的DataObject。您的代碼只需要首先檢查BitmapSourceAndFormat對象。如果發現它可以簡單地訪問它以獲得原始格式。如果不是,它必須訴諸於上述手段。

最後一個注意事項:對於剪貼板粘貼,您可以檢查可用的數據格式字符串。一些有用的是:Bitmap,Dib,Tiff,Gif,Jpeg和FileName。對於「Tiff」,「Gif」和「Jpeg」,您可以硬編碼所需的格式。對於「文件名」,您可以自己打開文件以獲取流傳遞給BitmapDecoder。對於沒有其他任何東西的「Dib」或「Bitmap」,您知道原始格式已丟失。

+0

哇 - 這是一個很好的答案。非常感謝!有關複製/粘貼的重要提示! – 2010-08-05 01:17:25

+0

+感謝不僅告訴我我想知道什麼,而且還告訴我我的根本問題是什麼!我應該更好地描述它。 – 2010-08-05 01:20:49

相關問題