位图操作心得

  最近要在公司项目里实现一个文档旋转的新 feature,所以有机会补上了一直以来都没怎么下过功夫的位图操作,这里把我的位图笔记摘出来一点分享一下,希望给那些想通过 SE 解决问题而不小心路过这里的朋友一些帮助:)

  先说说 DC 跟 bitmap 的关系吧,以前是从 WinAMP 视觉效果插件里面学到 memory DC 的运用的,看到人家先 CreateCompatibleDC() 再 CreateCompatibleBitmap() 就当公式记住了,从来没细想过为什么。这次在写程序的时候居然遇到了 SelectObject() “选”位图时返回 NULL 失败的现象,后来测试了一番再回头来查查《Windows 程序设计》才真正体会到了 compatible 是个什么意思。其实只有当 bitmap 跟 DC 的色深及 plane 数相同的时候 bitmap 才可以被选进 DC 里,这就叫 compatible,当然由于历史原因现在的 DC plane 就可以看作是常数 1 了。

  再来说说怎么样正确的创建彩色 bitmap,我开始的时候一直是用 CreateBitmap() 进行尝试的,结果总是会得到偏色和错位的位图,后来才在书上找到答案,CreateBitmap() 只能安全的用于创建单色位图,想通过位图数据创建彩色位图要通过其它途径。拿到彩色 bitmap 数据后要先调用 CreateBitmap() 创建一个跟 DC 兼容的位图,但最后一个参数要填 NULL,否则创建出来的位图肯定是失真的。等到用 CreateBitmap() 创建出位图后再用 SetDIBits() 给 HBITMAP 设置位图数据就可以得到彩色位图了。

  我对 GetDIBits() 和 SetDIBits() 一开始有个认识上的误解,以为位图是什么格式的就只能得到什么格式的位图数据,这样的话要针对 1、8、16、24、32 位色深分别写 5 份代码才能处理所有的位图格式,而且 16 位色又比较麻烦,后来看了 CodeProject 上的一个例子才知道,原来 GetDIBits() 和 SetDIBits() 的功能比我想象中的强大的多!你可以从 bitmap 中得到任意格式的位图数据,只要正确的设定参数和计算位图缓存的大小就可以了。这样通过 GetDIBits() 拿到 32 位色位图数据后就可以方便的实现各种特效了。

  在使用 GetDIBits() 和 SetDIBits() 的时候,BITMAPINFO 参数里面的位图高度也有点小九九,因为这里 bitmap 高度的符号决定了生成位图和获取位图数据时的扫描方向,正整数是从下往上,负整数是从上往下。如果你的程序生成的位图产生了镜像效果,那么多半调整一下这里的符号就可以恢复正常了。

  虽然由于以前大学时学 GUI 编程的时候跳过了这部分导致这次走了不少弯路,后来查书发现有些东西书上已经写得比较清楚了,不过自己尝试一下再得出结论还是要深刻和明白的多!

  后来在进行位图旋转算法优化的时候被公司里的算法牛人“教育”了一下,呵呵,收获不少,也看出了差距,别的不多说,还是要好好学习,天天向上呀!

Leave a Reply