|
基于IImgCtx的图像解码器 作者:马健 一、为什么要使用IImgCtx进行图像解码?在Windows下开发图像显示、图像处理软件的时候,第一步要面对的就是图像解码。目前免费的图像解码代码不少,单独的包括:
如果觉得一个、一个去找这些源代码太麻烦,也可以使用Davide Pizzolato开发的CxImage,其中集成了对大多数常见图像格式的解码源代码。 但是在我用过这些源代码后,也发现一些问题:
所以我和其它一些“懒”程序员一样,也希望能够找到一个像Windows API那样,用起来方便,生成的代码又小的通用图像解码器。 根据我在网上看到的资料,我最先考虑使用Windows本身提供的IPicture接口。这个接口在MSDN中有非常详细的说明,在codeguru、codeproject上也有详细的例子可供参考,用起来很方便。可惜的是,这个接口只能解码BMP、WMF、ICO、GIF、JPG格式(公开文档只承认可以解BMP、WMF、ICO)的图像,对PNG、TIFF格式无效。 后来在安装Windows系统的时候,我发现缺省情况下,Windows下GIF、PNG、JPG文件都被关联到了IE浏览器,再仔细想想,这些图像都经常在网页中出现,所以IE支持他们也没有什么好奇怪的。那么IE内核有没有提供什么接口,就好像可以用IHTMLDocument解析HTML源代码一样,可以供我们进行图像解码呢? 答案是:有的,就是IImgCtx接口。这个接口可以解码所有能够在IE中显示的图像格式,包括JPG、PNG、GIF、BMP、WMF、ICO,有时也能解TIFF(后面我会解释为什么说“有时”)。 二、如何使用IImgCtx进行图像解码?在我手头的IE 5.5 SDK包中,有对IImgCtx接口的完整定义(在IImgCtx.h文件中),在VC++ 6的安装目录中,也有对这个接口的定义,文件名一样,文件内容也只差了一行:IE 5.5 SDK包中多定义了一个常量DWN_MIRRORIMAGE,估计是IE 5.5比IE 4多出来的东西,可以对解码出来的图像进行镜像翻转。 但是不要说在MSDN中找,就算是用google搜,也找不到对这个接口的任何说明。好在这个接口比较简单,从接口定义还能大致猜测到它的用法:
DECLARE_INTERFACE_(IImgCtx, IUnknown)
{
#ifndef NO_BASEINTERFACE_FUNCS
/* IUnknown methods */
STDMETHOD(QueryInterface)(THIS_ REFIID riid,
LPVOID FAR* ppvObj) PURE;
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
STDMETHOD_(ULONG, Release)(THIS) PURE;
#endif
/* IImgCtx methods */
/* Initialization/Download methods */
STDMETHOD(Load)(THIS_ LPCWSTR pszUrl, DWORD dwFlags) PURE;
STDMETHOD(SelectChanges)(THIS_ ULONG ulChgOn,
ULONG ulChgOff, BOOL fSignal) PURE;
STDMETHOD(SetCallback)(THIS_ PFNIMGCTXCALLBACK pfn,
void * pvPrivateData) PURE;
STDMETHOD(Disconnect)(THIS) PURE;
/* Query methods */
STDMETHOD(GetUpdateRects)(THIS_ struct tagRECT FAR* prc,
struct tagRECT FAR* prcImg, long FAR* pcrc) PURE;
STDMETHOD(GetStateInfo)(THIS_ ULONG FAR* pulState,
struct tagSIZE FAR* psize, BOOL fClearChanges) PURE;
STDMETHOD(GetPalette)(THIS_ HPALETTE FAR* phpal) PURE;
/* Rendering methods */
STDMETHOD(Draw)(THIS_ HDC hdc,
struct tagRECT FAR* prcBounds) PURE;
STDMETHOD(Tile)(THIS_ HDC hdc, struct tagPOINT FAR* pptBackOrg,
struct tagRECT FAR* prcClip, struct tagSIZE FAR* psize) PURE;
STDMETHOD(StretchBlt)(THIS_ HDC hdc, int dstX, int dstY, int dstXE,
int dstYE, int srcX, int srcY, int srcXE, int srcYE,
DWORD dwROP) PURE;
};
从接口上看,在创建IImgCtx接口对象后,可以用Load方法调入图像文件,解码完成后即可用Draw方法显示了,不过:
用IImgCtx进行解码的详细过程见实例文件中的WndImgCtx.cpp。 三、如何将实例源代码集成到VC++工程中?本文提供的实例包含在ImgViewer.zip中,解开后是一个完整的VC++ 6工程。其中除了包含用IImgCtx对图像进行解码的代码外,还包含一个对目录中的文件进行搜索、排序,实现顺序浏览目录中所有图像的实例代码。 如果只需要使用图像解码部分,将WndImgCtx.h、WndImgCtx.cpp包含到你的工程中,在需要用到解码功能的CPP文件开头加入: #include "WndImgCtx.h" 然后就可以调用 HBITMAP GetBitmapFromFile(LPCTSTR pszFilename); 函数进行解码。从函数原型上即可看出,这个函数传入一个文件路径,返回一个DDB句柄。 如果需要包含顺序显示目录下所有图像的功能,将SrchDir.h、SrchDir.cpp、DirMng.h、DirMng.cpp包含到你的工程中,具体使用方法见MainFrm.cpp中的相关代码。 从使用的效果来看,在Windows 98/Me下,IImgCtx解码TIFF文件的时候有问题,在MSDN上也有几篇文章讨论在98/Me下IE显示不了TIFF的文章,不过照文章上说的进行设置,好像还是不行。在Windows 2000/XP下则没有什么问题。 四、为什么TIFF文件是一个例外?IE几乎支持所有常见图像格式,包括JPEG、PNG、GIF等,但是在IE的“打开文件”对话框中,唯独不见TIFF。我用libtiff组织提供的TIFF图像例子,测试本文提供的图像浏览器实例,结果发现在98/Me/XP下,一个TIFF文件也打不开;在Windows 2000下,能够打开差不多一半,另一半打不开。 在Windows 2000下,在VC 6中按Debug模式编译、运行ImageViewer,打开TIFF文件,退出,在Output窗口中可以看到下列行: Loaded 'C:\WINNT\system32\imgutil.dll', no matching symbolic information found. Loaded 'C:\WINNT\system32\tifflt.dll', no matching symbolic information found. Loaded 'C:\WINNT\system32\oieng400.dll', no matching symbolic information found. Loaded 'C:\WINNT\system32\mscms.dll', no matching symbolic information found. Loaded 'C:\WINNT\system32\winspool.drv', no matching symbolic information found. 而在Windows XP下,只能看到第一行,没有后续的行。 在Windows 2000中,运行regedit,然后搜索tifflt.dll,可以看到它提供“TIFFilter Class”,CLSID为 {EBD0F6B6-4AED-11D1-9CDB-00805F0C62F5} 。再继续在regedit32中搜索这个CLSID,可以在 HKEY_CLASSES_ROOT\MIME\Database\Content Type\image/tiff 项中,看到 Image Filter CLSID 为这个值。在这个项的前面,还有 image/png、image/jpeg 等项,它们都有 Image Filter CLSID 这个键。从MSDN提供的文档可以知道,HKEY_CLASSES_ROOT\MIME\Database\Content Type 项下列出的是IE能够识别的所有MIME type,MIME type一般从web server返回的HTML包头提取。 从 Image Filter CLSID 这个键的名称来看,这个CLSID记录的应该就是图像解码器的CLSID。在Windows 98/Me/XP下运行regedit32,查找到HKEY_CLASSES_ROOT\MIME\Database\Content Type\image/tiff项,在它下面并没有 Image Filter CLSID 这个键。而在 image/png、image/jpeg 等项下面,都有这个键。这个大概就是为什么在Windows 98/Me/XP下,IE 无法解码TIFF文件的原因:没有对应的解码器。 我曾经尝试过将tifflt.dll移至到Windows XP下,但是因为DLL冲突,没有成功。看来要想在2000以外的Windows平台下显示TIFF文件,只有等待微软推出对应的TIFF解码器了。 五、进一步的练习实例代码虽然演示了一个图像浏览器的最原始功能,但是要想成为一个真正的图像浏览器,还有很多需要改进的地方,有兴趣的可以试一下,就当做是练习好了:
|