65.9K
CodeProject 正在变化。 阅读更多。
Home

基于 IImgCtx 的图像解码器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (20投票s)

2004年5月17日

5分钟阅读

viewsIcon

187308

downloadIcon

3397

本文展示了如何使用 IE 提供的 IImgCtx 接口解码图像

1. 为什么我使用 IImgCtx 来解码图像?

如果你想在 Windows 中开发图像查看器或图像处理器,首先需要面对的就是图像解码。现在有一些免费的图像解码器,带有完整的源代码

如果你希望在一个项目中包含所有解码器,可以尝试 CxImage,它由 Davide Pizzolato 开发。

但在尝试了以上所有解码器之后,我也发现了一些问题

  • 它们很难使用。在我能够编译它们之前,我必须配置或定制源代码。
  • 它们很难调试。大多数免费解码器是用 C 编写的,注释很少。
  • 所有解码器都会被嵌入到 EXE 或 DLL 中,这会让安装包变得非常大。当然,如果最终用户愿意购买一个“大”的安装包,那又是另一回事了。

所以,我(以及其他“懒惰”的程序员)一直希望有一个图像解码器:易于使用,占用空间小,一个解码器支持所有图像。

根据我在网上获得的信息,我尝试的第一个工具是 IPicture 接口,它在 MSDN 中有很好的文档记录,并在 codeguruCodeProject 上有过讨论。好消息是:尽管 MSDN 说 IPicture 只能解码 BMP、WMF 和 ICO 文件,但它实际上也能很好地处理 GIF 和 JPG。坏消息是:它确实无法解码 PNG 和 TIFF。

然后,当我重新安装我的 Windows 操作系统时,我发现 GIF、JPG、PNG 文件的默认查看器是 Microsoft Internet Explorer (IE)。由于所有这些类型的图像经常用在网页上,所以 IE 支持它们是合理的。那么,IE 是否提供了像我用来解析 HTML 代码的 IHTMLDocument 接口一样的接口来解码图像呢?

答案是:是的,它就是 IImgCtx 接口。它可以解码所有能在 IE 中显示的图像,包括 JPEG、PNG、GIF、BMP、WMF、ICO,有时也包括 TIFF(我稍后会解释为什么说“有时”)。

2. 如何使用 IImgCtx 接口来解码图像?

在 IE 5.5 SDK 中(这是我唯一拥有的 IE SDK),我在 IImgCtx.h 文件中找到了 IImgCtx 接口的定义。在 VC++ 6 中,我也找到了那个文件。两个文件之间只有一个行的区别:在 IE 5.5 SDK 中,它额外定义了一个名为 DWN_MIRRORIMAGE 的常量值。我认为这也是 IE 4 和 IE 5.5 之间的区别。

但是当我尝试在 MSDN 中搜索 IImgCtx 时,一无所获。然后我尝试在 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 的定义,在我创建 IImgCtx 对象后,可以使用 Load 方法读取图像文件。然后可以使用 Draw 方法显示解码后的图像。但是
  • Load 方法的参数是一个 Unicode 格式的 URL(因为是 IE 的?)。所以我必须将本地路径名转换为 file://local path 的格式。
  • 与其他 IE 中的接口一样,IImgCtx 也以异步方式工作。这就是为什么它定义了 SetCallback 方法来设置回调函数,以及 SelectChanges 方法来监控状态。由于没有任何关于 IImgCtx 的文档,我不知道如何使用它们。我只知道我必须构建一个消息循环来驱动异步进程。
  • Draw 方法使用一个 HDC 作为目标设备上下文。如果这是一个内存 DC,它可以在不显示图像的情况下对其进行解码。解码后的图像是一个 DDB(设备相关位图)。如果你想处理它,最好将其转换为 DIB(设备无关位图)。

使用 IImgCtx 接口解码图像的完整过程在示例项目中的 WndImgCtx.cpp文件中展示。

3. 如何在你的项目中 M2N7使用 IImgCtx

本文的示例代码是 ImgViewer.zip。下载并解压它,你会得到一个简单的(确实非常简单)图像查看器的 VC++ 6 项目。除了图像解码器,它还展示了如何搜索和排序文件夹中的文件,以便你可以逐个查看图像。

如果你只想一个图像解码器,可以将WndImgCtx.h 和 WndImgCtx.cpp包含到你的项目中,并在你的 CPP 文件的开头添加这一行:

#include "WndImgCtx.h"

然后你就可以调用:

HBITMAP GetBitmapFromFile(LPCTSTR pszFilename);

来解码图像。它将返回一个由 HBITMAP 标识的 DDB。

4. 为什么 TIFF 是例外?

IE 支持大多数图像文件,包括 JPEG、PNG 和 GIF。但在 IE 的“文件打开”对话框中,我找不到 TIFF 文件。我用 libtiff 组织提供的示例文件测试了 ImgViewer。结果是:在 Windows 98/Me/XP 中,它们都无法显示。在 Windows 2000 中,大约有一半可以显示,另一些则不能。

在 Windows 2000 中,我用 VC++ 6 的 Debug 模式编译并运行 ImgViewer,打开一个 TIFF 文件,然后退出。我在 VC++ 的输出窗口中发现了以下几行:

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}。然后我再次搜索这个 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 类型。

从 "Image Filter CLSID" 的名称来看,我猜测这就是图像过滤器的 CLSID。在 Windows 98/Me/XP 中,我在 "image/tiff" 项下找不到它。但在 "image/png" 和 "image/jpeg" 项下可以找到。也许这就是为什么 IE 在 Windows 98/Me/XP 中无法显示 TIFF 的原因:没有用于它的图像过滤器。

我尝试将 tifflt.dll 和 oieng400.dll 移动到 XP 中,但由于 DLL 冲突而失败。也许唯一的希望是:Microsoft 提供一个 TIFF 的图像过滤器。

© . All rights reserved.