博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

一笑

slimzhao.cublog.cn


.NET 中关于ImageList 管理0-255级Alpha通道解决方法
.NET之前, 微软乃至微软之外的公司/软件已经以极好的效果处理图片了, 包括对Alpha通道的支持, .NET是后来者, 但是先天却对这个支持不足.

说这话时, 我用的已经是VS2008, 看一下在VS2008本身里面打开calc.exe(计算器)的效果:



看见最后三个图标的黑边没有, 操作系统本身显示这样的图标时绝不是这个效果, 第三方软件如Icon Workshop专门处理图标的, 对这个的支持自然也很完美.

我是在解决一个程序界面上一个看似bug的不完美之处时左冲右突最后阴差阳错在VS2008 中打开calc.exe时看到这个效果的, 正是因为这个效果, 让我开始怀疑这是.NET本身的bug所致.

果然, google结果都证实了这一点, 在.NET中 ImageList被广泛用来管理和显示ListView 等众多控件中的图像相关资源. 但是通过.NET form designer来给ImageList添加图像时, 其Alpha通道会被错误处理, 并不是简单地丢失或忽略, 而是看上去有部分的支持. 即对半透明的像素它给处理成完全不透明了. 对安全透明的像素还是可以正确处理的, 最终的视觉效果就是一些图标的边缘有锯齿效果, 很粗糙.

code project上两个文章分别解决了关于ImageList的两个不怎么相关的问题.

其一就是解决ImageList的内置Add 方法错误处理Alpha通道的. 地址在:
http://www.codeproject.com/KB/miscctrl/AlphaImageImagelist.aspx

解决的很好, 充分考虑了各种向ImageList添加图像的来源, 图像文件, Assembly中的内嵌资源. 缺点有这么几个:
1. 跟Form Designer的机制脱节, 可以在代码里通过它提供的接口向ImageList 添加图像资源--完美保留ALpha通道, 但是在设计期跟你的ImageList的内容是不相关的, 它没办法让你在设计期就能看到ImageList中添置好的图像资源, 也因此让你的其它控制无法选取该资源, 比如一个Button选择ImageList中的某个图像作为其背景, 这没法办到, 除非你另外通过Form Designer向ImageList中添加资源--- 但这个资源无疑是不能正确包含Alpha通道的. 你得手工保证运行期 ImageList中通过该控制添加的内容与设计期开发者看到的效果是一致的, ImageIndex 尤其要保证, 对于.NET 2.0而言, 还得保证ImageKey.

2. 通过Assembly内嵌资源添加图像时, 接口如下:
public static void AddEmbeddedResource( string resourceName, ImageList destinationImagelist);

第一个是资源名, 第二个参数是ImageList(的引用).

该函数在内部确定嵌入了该资源的Assembly是:
Assembly.GetExecutingAssembly().GetManifestResourceStream( resourceName );

这就带来了一个问题, 如果希望这个可重用的组件独立编译在一个DLL中, 从而被其它众多项目共用的话, 那些图像资源往往是嵌入在那些使用它的项目的目标Assembly中, GetExecutingAssembly()则永远返回当前正在执行的那么指令所置身其中的那个Assembly, 也就是你独立编译出来的DLL中, 所以这样来得到Assembly是不行的, 我对它的一点改动是:
public static void AddEmbeddedResource(Assembly assembly, string resourceName, ImageList destinationImagelist);
多传进来一个Assembly参数. 这样调用者可以决定资源是在哪个Assembly中的.

再看第二个项目:
http://www.codeproject.com/KB/selection/ImageListAssigner.aspx
它解决的是在.NET的Form designer中, 默认的ImageList编辑器不好用的问题, 它集成到.NET 的Form designer中, 提供了一个确实更好用更方便的编缉器.
但是, 它丝毫没有触及第一个项目中解决的Alpha通道问题.

现在, 两位作者确实都解决了ImageList的一些方便, 是站在他们肩膀上的时候了.

把两个项目一结合, 略加修改, 就得到了一个比.NET Form Designer中内置的ImageList编辑器更好用的可视界面, 而且完美支持图像的Alpha通道. 不过严格说, 离完美还差一点, 下面的截图中会看到, 程序的最终运行效果是好的, 但在Form Designer中开发者在设计时看到的却差一些, 这总比事情反过来好, 开发者看到的效果再好, 如果程序运行时最终用户看到的更差, 那等于没做.

下面是VS.NET 2003中的截图:

一脸麻点的窗口自然是设计时的Form Designer窗口, 可以看到Alpha通道被处理的很差, 显示为全黑色, 而那个ImageListAssigner窗口显示的也是一样, 最上层的窗口显示的是实际运行时的效果, 透明效果完全出来了.

要出来这个效果还有一点是必需的, 就是上图中红线框起来的两行, 语句简单, 但里面的内在机制比较复杂, 这两行必需出现在任何UI代码运行之前. 而且, 无论是对VS2003还是VS2008都必需这样, 有另外一个work around的办法替代这红框里的现行代码是, 使用manifest文件. 这儿不多说这个.

下面的是VS2008中的效果:




可以看到在Form Designer设计时边缘效果比较差(但比VS2003好一些, 那个是完全的黑框), 但ImageListAssigner窗口和和运行时其效果都是完美的.

有一个极小的细节: 在一个特殊的时刻, VS2008 即使是Form Designer中也可以显示出完美的透明效果, 那就是 ImageListAssigner窗口的 "Apply"刚刚被点击之后, 此时VS.NET得到了一个ImageList, 其中的图像的Alpha通道是ImageListAssigner 刚刚做好新出炉的, 但是, 重新rebuild项目或其它一些操作, 会引发VS.NET从资源中的base64编码重新生成ImageList, 边缘锯齿就又回来了, 回来不要紧, 因为这只是从resx资源到VS.NET内部使用的ImageList的单向流动, 千万不要造成VS.NET再把这个ImageList写回resx中, 那时透明效果就会又被它搞砸锅.



通过ImageListAssigner 来编辑ImageList之后,
在属性窗口和ImageList的编辑器中, VS2008的显示也更好一些:


08中的透明效果出来了, 虽然图像小小的怎么都看不清楚.

未征得原作者同意, 暂不发布修改后的结果.

发表于: 2008-05-07 ,修改于: 2008-05-07 21:39,已浏览169次,有评论0条 推荐 投诉


网友评论

发表评论