帮人做一个遥感数字图像处理的小功能,其中的数据源是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(调色板)对象()。 那么是否能够直接对这个属性赋值呢? 似乎有难度,因为“调色板”没有一个公开的构造方法。于是谷歌了一下解决方法,有一位网友是这么做的:Bitmap bmpTemp = new Bitmap (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的,还是改了吧。