基于IImgCtx的图像解码器

原创 2004年05月25日 10:20:00

作者:马健
邮箱:stronghorse@tom.com
主页:http://stronghorse.yeah.net

一、为什么要使用IImgCtx进行图像解码?

在Windows下开发图像显示、图像处理软件的时候,第一步要面对的就是图像解码。目前免费的图像解码代码不少,单独的包括:

  • Independent JPEG Group(独立JPEG小组)发布的专门解JPEG格式的源代码
  • libpng组织提供的专门解png格式的源代码
  • libtiff组织提供的专门解TIFF格式的源代码
  • giflib组织提供的专门解gif格式的源代码

如果觉得一个、一个去找这些源代码太麻烦,也可以使用Davide Pizzolato开发的CxImage,其中集成了对大多数常见图像格式的解码源代码。

但是在我用过这些源代码后,也发现一些问题:

  • 用起来太麻烦了,不仅在编译的时候需要对编译参数进行设置,而且解码后的图像用起来也麻烦。
  • 可靠性令人怀疑,而且在出错后,跟踪、调试太难了,那一大堆C代码不是好玩的。
  • 所有的解码代码都需要嵌入编译后生成的EXE文件,或DLL中,增加了最终发行包的尺寸。当然如果最终用户希望到手的是一个“大型软件”,则另当别论。

所以我和其它一些“懒”程序员一样,也希望能够找到一个像Windows API那样,用起来方便,生成的代码又小的通用图像解码器。

根据我在网上看到的资料,我最先考虑使用Windows本身提供的IPicture接口。这个接口在MSDN中有非常详细的说明,在codegurucodeproject上也有详细的例子可供参考,用起来很方便。可惜的是,这个接口只能解码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方法显示了,不过:
  • Load方法中的参数指明是一个URL(估计是IE内核的要求),因此需要将本地文件名转换成file://开头的URL,并且必须使用Unicode编码。
  • 与IE中的其它接口一样,IImgCtx工作过程也是异步的,所以才需要SetCallback方法设置回调函数,SelectChanges方法对状态进行监视,不过由于实在找不到什么资料,所以我也不知道这两个接口怎么用。我只知道对于这种异步处理过程,必须创建消息泵,对解码过程中产生的消息进行分发,否则解码过程会被吊住。
  • Draw方法允许传入一个HDC作为目标DC,如果这个HDC是一个内存DC,即可不显示,直接在内存中对图像进行解码。解码出来的图像是DDB,再转换成DIB后,即可进行常规图像处理。

用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解码器了。

五、进一步的练习

实例代码虽然演示了一个图像浏览器的最原始功能,但是要想成为一个真正的图像浏览器,还有很多需要改进的地方,有兴趣的可以试一下,就当做是练习好了:

  1. 支持在线浏览。其实IImgCtx本身就支持对网络图片进行解码,而且可以边解码边显示,就象在IE中一样。
  2. 支持从内存中显示图片,而不是读文件。这个需要一定的技巧,可以有两种简单点的办法:一种是架势web服务器,解码器按照http协议获取图片。在codeguru和codeproject上,有很多现成的web server代码,直接拿来用就好,自己只要考虑怎么填写返回内容即可。VC 6自带的MSDN光盘上,也带了一个名为HTTPSVR的例子,说明如何用MFC和WinSock创建web server。另一种是使用Asynchronous Pluggable Protocols(协议插件),到MSDN、codeguru和codeproject上搜索这几个关键字,从理论到源代码都能找出一堆,在这里我就不罗嗦了。
  3. 图像居中显示。这个相对容易一些。
  4. 对于大图像,支持用鼠标拖拽。这个应该是有现成例子可供参考,找一下吧。
  5. 支持图像处理。这个可以参考CxImage,它支持将DDB转换成DIB,然后对DIB进行各种处理。不过如果不使用其它图像编码代码的话,编辑完的图像大概只能存储成BMP文件。
  6. 支持浏览子目录下的图片。SrchDir.h、SrchDir.cpp、DirMng.h、DirMng.cpp都是我从ComicsViewer源代码中拷贝过来的,不过做了很多简化,有兴趣的可以再把我简化掉的东西试着补回去。

H.264解码器中参考图像的管理

H.264解码器中参考图像的管理Peter Lee 2005.11.24 videosky.9126.com 【写在前面】由于H.264采用了多参考帧预测技术,所以其参考图象的管理比较复杂。GO50只...
  • sunshine1314
  • sunshine1314
  • 2006年01月10日 20:15
  • 15495

最简单的基于FFMPEG+SDL的音频播放器:拆分-解码器和播放器

本文补充记录《最简单的基于FFMPEG+SDL的音频播放器》中的两个例子:FFmpeg音频解码器和SDL音频采样数据播放器。这两个部分是从音频播放器中拆分出来的两个例子。FFmpeg音频解码器实现了视...
  • leixiaohua1020
  • leixiaohua1020
  • 2015年07月17日 09:31
  • 11876

Internet常见图像格式及其在Linux上的处理

图象格式简介kerberos软件工程师, 蓝点软件北京研发部2001 年 2 月 许 多应用程序需要处理 Internet上的图象信息。这些图象信息通常以特定的格式保存,常见的有GIF...
  • sunrock
  • sunrock
  • 2005年04月19日 16:01
  • 1560

Real-Time Rendering (4) - 基于图像的绘制(Image-Based Effects)

用多边形来描述3D场景中的物体是最简单的一种方法了,但也有它的局限,有的时候基于图像的渲染(Image-bases rendering),有些场合IBR会更受用一些,它是基于图像数据的渲染。用图像来表...
  • qp120291570
  • qp120291570
  • 2013年12月05日 23:38
  • 4574

基于内容图像检索

图像检索:基于内容的图像检索技术  2016年06月05日  图像检索  图像检索 字数:6890 背景与意义 在Web2.0时代,尤其是随着Fl...
  • u013087984
  • u013087984
  • 2016年07月26日 19:48
  • 7043

基于MATLAB的图像处理程序(…

原文地址:基于MATLAB的图像处理程序(全文转载)作者:星夜图像变换(傅立叶变换), 图像增强, 边缘检测, 滤波, 图像压缩等. 实验工具:MATLAB软件 课程设计时间:2008年12月 实 验...
  • wangxiaofei558
  • wangxiaofei558
  • 2016年05月23日 10:34
  • 3756

ufldl 深度学习入门 第5发 线性解码器

这一节其实很简单,所谓线性解码器,就是将输出层的激活函数换成了线性函数,其他的没有变。 输出层用线性函数替代sigmoid函数的目的是使输出不再受限在[0,1]范围内。 数据集采用STL-10 彩色图...
  • sloanqin
  • sloanqin
  • 2015年10月10日 20:53
  • 759

第9章 基于水色图像的水质评价

背景与挖掘目标根据数码相机采集的水色照片对水质进行自动评价。我个人对这个评价中的采样过程是有意见的,如果对周围环境不做严格限制,数码相机采样得到的结果本身差异度就很大,用来做样本是不合理的。不过做为练...
  • qq_26978413
  • qq_26978413
  • 2017年10月31日 10:11
  • 190

基于卷积神经网络的图像语义分割

摘要           传统的图像分割方法大部分是基于图像本身的特征提取,需要先在图像上生成不同的区域,再在区域上提取特征,对区域进行分类合并才能得到最终语义分割的结果,过程比较复杂,并且效果也有很...
  • xiaofei0801
  • xiaofei0801
  • 2017年06月28日 17:00
  • 579

基于FPGA的图像处理(六)--Shared Memory

在FPGA的设计中,当不同速率的模块之间进行高速的数据传输时,共享存储器是一个很好的解决方案,在一个模块中将数据写入Shared Memory,在另一个模块中将其读出,Shared Memory使用n...
  • renshengrumenglibing
  • renshengrumenglibing
  • 2012年11月30日 09:31
  • 2528
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于IImgCtx的图像解码器
举报原因:
原因补充:

(最多只允许输入30个字)