幫人做一個遙感數字圖像處理的小功能,其中的數據源是Landset圖像,八位灰度。
然而Winform真的太弱了,System.Drawing下的PixelFormat(像素格式)枚舉居然沒有提供八位灰度模式,無奈只好用
PixelFormat.Format8bppIndexed(八位顏色索引)替代,可是問題又來了···
要使顏色索引模式生效,必須在Bitmap的調色板中設置每個索引到具體的顏色的映射:
for (int i = 0; i < 256; i++)
{
// 每一個灰度映射到一種顏色
bmp.Palette.Entries[i] = Color.FromArgb(i, i, i);
}
運行結果,圖像呈現了一種藍色色調,沒有在灰度模式下顯示。
我找到了bmp.Palette的定義,Bitmap的Palette屬性可讀可寫,是一個ColorPalette(調色板)對象(MSDN鏈接)。
那麼是否能夠直接對這個屬性賦值呢?
似乎有難度,因為“調色板”沒有一個公開的構造方法。於是谷歌了一下解決方法,有一位網友是這麼做的:
Bitmap bmpTemp = newBitmap(1, 1, PixelFormat.Format8bppIndexed);
ColorPalette palette = bmpTemp.Palette;
for (int i = 0; i < 256; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
bmp.Palette = palette;
特別構造了一個臨時的Bitmap,為的就是取他的調色板。運行後,確實有效,灰度圖像正常顯示。
有沒有不用更容易的辦法呢?有!我在後面的嘗試當中,發現了另一種方法:
ColorPalette palette = bmp.Palette;
for (int i = 0; i < 256; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
bmp.Palette = palette;
和第一段代碼沒有什麼差別啊,只是定義一個新的變量來保存bmp.Palette。這段代碼如何能夠起作用呢?
但確實起作用了···
按照正常的思維,ColorPalette是引用類型,所以palette只是複製了bmp.Palette的引用,最後一句把自己的引用重新賦值回來應當沒有用處,因此效果和第一段代碼應當一樣!!
既然MSDN不能解決疑惑,那只有求助於Reflector了。
在Bitmap的父類Image中,找到了Palette屬性的實現:
public ColorPalette get_Palette()
{
return this._GetColorPalette();
}
private ColorPalette _GetColorPalette()
{
······
ColorPalette palette = new ColorPalette(size);
IntPtr ptr = Marshal.AllocHGlobal(size);
······
return palette;
}
很明顯,Bitmap.Palette並沒有像普通的屬性一樣,返回對應字段的引用,而是複製了一份新的。這就好的解釋了為什麼第一段代碼完全沒有效果。
當然,這樣的類用起來實在不爽,不瞭解他的內部構造,就沒有辦法正常使用。能改用WPF的,還是改了吧。