2013-10-31 34 views
7

根據我在SO和Web上的研究,保存位圖時的GDI +通用錯誤顯然是一個常見問題。給定以下簡化片段:GDI +使用LockBits從內存創建的通用錯誤保存位圖

byte[] bytes = new byte[2048 * 2048 * 2]; 

for (int i = 0; i < bytes.Length; i++) 
{ 
    // set random or constant pixel data, whatever you want 
} 

Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale); 
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, 2048, 2048), ImageLockMode.ReadWrite, bmp.PixelFormat); 
System.Runtime.InteropServices.Marshal.Copy(bytes, 0, bmpData.Scan0, 8388608); 
bmp.UnlockBits(bmpData); 
bmp.Save(@"name.bmp"); 

這會導致0x80004005一般錯誤。據說通常的原因是對組件的鎖定,但我在這裏沒有看到任何東西。我是否只是盲目的?我保存的路徑存在,當然,只有一個空的bmp文件被創建(0B)。

背景:我從使用C++/CLI包裝器傳輸到.NET的攝像頭驅動程序獲取像素數據,因此上述Bitmap對象通過函數調用返回。但由於這個小例子已經失敗了,我猜這個適配器沒有問題。

任何建議,非常感謝!

+0

16位灰度是不是一個有效的bmp格式可能? –

+0

老實說,我沒有考慮過這一點。切換到8bpp索引創建文件沒有任何錯誤。最終目標是將灰度16bpp圖像保存爲PNG,但用'bmp.Save(@「name.bmp」,ImageFormat.Png)替換上述內容;'也不起作用。 – simd

+0

保存時是否嘗試過指定ImageFormat.Bmp?看到這個答案:http://social.msdn.microsoft.com/Forums/vstudio/en-US/10252c05-c4b6-49dc-b2a3-4c1396e2c3ab/action?threadDisplayName=writing-a-16bit-grayscale-image – Ben

回答

15
Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale); 

GDI +的例外情況相當差,您將無法診斷出這兩個錯誤。較小的一個是您的Save()調用,它不指定要保存的ImageFormat。默認是PNG,而不是你所希望的。

但核心之一是PixelFormat.Format16bppGrayScale。當GDI +被設計出來,早在.NET出現之前,每個人都在使用CRT而不是液晶顯示器。 CRT顯示色域相當不錯。雖然好,但還沒有主流CRT能夠顯示65536個不同的灰色。大部分都受到視頻適配器中DAC的限制,該芯片將數字像素值轉換爲CRT的模擬信號。一個可以在100MHz或更高頻率下以16位精度轉換的DAC在技術上還不可行。微軟在顯示技術方面進行了冒險改進,以便有朝一日將如此指定的Format16bppGrayScale作爲像素格式,可能有一天可用。

這沒有發生。相反,LCD在色彩分辨率上明顯更差。典型的LCD面板只能解析6位的顏色,而不是像素格式中的8位。獲得16位色彩分辨率將需要重大的技術突破。

所以他們猜錯了,由於像素格式沒有用,GDI +實際上並沒有一個圖像編碼器可以編寫16bpp灰度圖像格式。 Kaboom在嘗試將其保存到磁盤時,無論您選擇的ImageFormat如何。

實際使用16bpp灰度,放射成像使用該像素格式。用非常昂貴的顯示器使其實際有用。然而,這樣的設備不變地使用自定義圖像格式,DICOM是通常的選擇。 GDI +沒有編解碼器。

您需要購買一個支持客戶想要的圖像格式的圖書館。鉛工具是該產品領域的千磅大猩猩。

+0

謝謝您的詳細回答,總是很高興爲您解釋一些背景知識。這裏指的是圖像不太適合用於顯示,而是之後用軟件進行分析。圖像來自延時顯微鏡,16bit給我們的選項比8bit多得多。因此,如果我必須使用一個額外的庫,那麼WIC是否會在這裏工作(已經在相機適配器中與它進行鏈接),還是必須回退到libpng? – simd

+3

在這種情況下,您完全不承諾支持的圖像格式。這裏要做的聰明的事情就是以自己的格式保存數據。例如,BinaryWriter無法做到這一點。 –

+1

16位位圖對範圍數據也很有用(例如Kinect生成的那樣) – Eponymous