2011-04-16 141 views
16

我發現大量人將BitmapSource轉換爲Bitmap,但ImageSource轉換爲Bitmap?我正在製作一個成像程序,我需要從Image元素中顯示的圖像中提取位圖。有誰知道如何做到這一點?C# - 將WPF Image.source轉換爲System.Drawing.Bitmap

EDIT 1:

這是用於轉換BitmapImageBitmap的功能。請記住在編譯器偏好設置中設置'不安全'選項。

public static System.Drawing.Bitmap BitmapSourceToBitmap(BitmapSource srs) 
{ 
    System.Drawing.Bitmap btm = null; 

    int width = srs.PixelWidth; 

    int height = srs.PixelHeight; 

    int stride = width * ((srs.Format.BitsPerPixel + 7)/8); 

    byte[] bits = new byte[height * stride]; 

    srs.CopyPixels(bits, stride, 0); 

    unsafe 
    { 
     fixed (byte* pB = bits) 
     { 
      IntPtr ptr = new IntPtr(pB); 

      btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr); 
     } 
    } 
    return btm; 
} 

下一頁現在是獲得BitmapImage

RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
    (int)inkCanvas1.ActualWidth, 
    (int)inkCanvas1.ActualHeight, 
    96d, 96d, 
    PixelFormats.Default); 

targetBitmap.Render(inkCanvas1); 

MemoryStream mse = new MemoryStream(); 
System.Windows.Media.Imaging.BmpBitmapEncoder mem = new BmpBitmapEncoder(); 
mem.Frames.Add(BitmapFrame.Create(targetBitmap)); 
mem.Save(mse); 

mse.Position = 0; 
BitmapImage bi = new BitmapImage(); 
bi.BeginInit(); 
bi.StreamSource = mse; 
bi.EndInit(); 

下一步是將其轉換:

Bitmap b = new Bitmap(BitmapSourceToBitmap(bi)); 

回答

21

其實你不需要使用不安全的代碼。有一個接受一個I​​ntPtr的CopyPixels過載:

public static System.Drawing.Bitmap BitmapSourceToBitmap2(BitmapSource srs) 
{ 
    int width = srs.PixelWidth; 
    int height = srs.PixelHeight; 
    int stride = width * ((srs.Format.BitsPerPixel + 7)/8); 
    IntPtr ptr = IntPtr.Zero; 
    try 
    { 
     ptr = Marshal.AllocHGlobal(height * stride); 
     srs.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height * stride, stride); 
     using (var btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr)) 
     { 
      // Clone the bitmap so that we can dispose it and 
      // release the unmanaged memory at ptr 
      return new System.Drawing.Bitmap(btm); 
     } 
    } 
    finally 
    { 
     if (ptr != IntPtr.Zero) 
      Marshal.FreeHGlobal(ptr); 
    } 
} 
+0

請注意,在內部,這個'Bitmap'的構造函數調用'GdipCreateBitmapFromScan0',它希望用戶在不再需要時釋放內存...... – Cameron 2014-03-17 13:45:20

+0

@Cameron,好點。我編輯了我的答案,將其考慮在內。 – 2014-03-17 15:37:32

+0

不幸的是,內存不能被釋放,直到System.Drawing.Bitmap被處置(我找不到任何文檔,但在互操作性應用程序中試用後,我的圖像只顯示正確,如果我之後免費,所以它看起來不像是在內部複製數據)。另外,[GDI文檔](http://www.jose.it-berater.org/gdiplus/reference/flatapi/bitmap/gdipcreatebitmapfromscan0.htm)似乎要求跨度是4的倍數;所以'(srs.Format.BitsPerPixel + 7)/ 8'應該是'(srs.Format.BitsPerPixel + 31)/ 32 * 8',我相信。 – Cameron 2014-03-20 20:34:40

2

是您的ImageSource不是的BitmapSource?如果你從它們應該加載的文件中加載圖像。

回覆您的評論:

聽起來像他們應該的BitmapSource那麼,是的BitmapSource ImageSource的子類型。將ImageSource轉換爲BitmapSource並遵循其中一個博文。

+0

沒有,它說,他們是ImageSources。我從Bitmap轉換的BitmapIamges中加載它們。 – user646265 2011-04-17 13:57:29

+0

謝謝,我想出了一種我相信可以正常工作的方法。我已發佈爲我的問題的編輯。 – user646265 2011-04-18 21:31:15

+0

@SimonStenderBoisen - 一個'ImageSource'可能來自'XAML'文件而不是'Bitmap'文件。如果是這樣,它的底層類可能是'DrawingBrush',需要轉換才能得到實際的'Bitmap'。 – 2015-11-10 17:58:02

1

你並不需要一個BitmapSourceToBitmap方法都沒有。只要做到創建內存流後執行以下操作:

mem.Position = 0; 
Bitmap b = new Bitmap(mem); 
2

這個例子爲我工作:

public static Bitmap ConvertToBitmap(BitmapSource bitmapSource) 
    { 
     var width = bitmapSource.PixelWidth; 
     var height = bitmapSource.PixelHeight; 
     var stride = width * ((bitmapSource.Format.BitsPerPixel + 7)/8); 
     var memoryBlockPointer = Marshal.AllocHGlobal(height * stride); 
     bitmapSource.CopyPixels(new Int32Rect(0, 0, width, height), memoryBlockPointer, height * stride, stride); 
     var bitmap = new Bitmap(width, height, stride, PixelFormat.Format32bppPArgb, memoryBlockPointer); 
     return bitmap; 
    }