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

图像查看器实用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (45投票s)

2001年12月10日

CPOL

18分钟阅读

viewsIcon

426862

downloadIcon

19355

一个小型实用程序,允许您在单步调试绘图代码时查看内存位图和设备上下文的内容。

Image Viewer Application showing the contents of a memory DC

图像查看器应用程序显示图像列表的内容

目录

引言

您是否曾经在调试图形例程时,非常希望在单步执行代码时能看到内存中正在处理的图像的实际样子?现在,您可以了!

图像查看器是一个简单的实用程序,您可以将其插入到您的绘图代码中。它具有缩放功能,因此您可以非常仔细地查看您正在绘制的内容,或者获得更大图片的全貌。用它来查看 HDCHBITMAPHICONHCURSORHFONTHIMAGELISTHRGNGdiplus::Image

图像查看器下载包仅包含已编译的文件和 ImageViewer.h 头文件。演示应用程序下载包包含所有源代码。

ImageViewer.h 头文件和 ImageViewer.dll 库文件都是仅使用 Win32 API 和一些 ATL 编写的。没有使用 MFC。头文件和库文件都已在 Visual C++ 6.0 和 Visual C++ 8.0 上进行了测试,支持 MBCS 和 Unicode 构建。

系统要求

由于图像查看器应用程序是一个 32 位 MFC 8.0 Unicode 应用程序,您需要在您的机器上安装 Visual C++ 8.0 运行时才能使用它。运行时可以从微软网站获取。按照该页面上的说明下载并安装 vcredist_x86.exe 运行时安装程序。图像查看器应用程序还使用了 GDI+。如果您运行的是 Windows 2000,您可能需要从微软网站下载并安装 GDI+ 可再发行文件。

安装文件

没有提供安装程序,因此必须手动将文件复制到硬盘上的适当位置。所有必要文件都包含在图像查看器实用工具下载文件中。

文件 所在文件夹
ImageViewer.h Dev Studio\VC\Include
ImageViewer.dll WindowsWINNT
ImageViewer.lib Dev Studio\VC\Lib
ImageViewer.exe Dev Studio\Common\Tools

如何使用图像查看器

使用这个实用工具非常简单。只需在包含绘图代码的源文件中包含 ImageViewer.h 头文件即可。通过定义 ACTIVATE_VIEWER 宏来启用查看器。

// viewer active

#define ACTIVATE_VIEWER
#include "ImageViewer.h"

// viewer not active

// #define ACTIVATE_VIEWER

#include "ImageViewer.h"

如果定义了 ACTIVATE_VIEWER,并且您在调试模式下工作,ImageViewer.h 文件将使您的程序链接到 ImageViewer.lib 文件,并且当您的程序执行时,它将加载 ImageViewer.dll 文件。

要实际查看图像,您必须运行 ImageViewer.exe 程序。DLL 将使用 WM_COPYDATA 消息将要查看的位图发送到查看器应用程序。

在您的绘图代码中,每当您想查看图像时,就调用一个 Show* 函数。

CDC memDC;
memDC.CreateCompatibleDC(NULL);

// some drawing code


ShowDC(memDC); // take a peek at what is drawn so far


// some more code etc.

如果图像查看器工具处于活动状态,则会定义 VIEWER_ACTIVE 宏,因此您可以通过检查 VIEWER_ACTIVE 宏来控制 Show*() 宏周围的额外代码。

#ifdef VIEWER_ACTIVE

// Some code that requires the image viewer tool


#endif // VIEWER_ACTIVE

API 宏

API 由以下宏组成:

  • ShowBitmap (HBITMAP bmp)
  • ShowBitmap2 (HBITMAP bmp, LPCTSTR Text)
  • ShowDC (HDC DC)
  • ShowDC2 (HDC DC, LPCTSTR Text)
  • ShowGDIPlusBitmap (Gdiplus::Image)
  • ShowGDIPlusBitmap2 (Gdiplus::Image, LPCTSTR Text)
  • ShowIcon (HICON icon)
  • ShowIcon2 (HICON icon, LPCTSTR Text)
  • ShowCursor (HCURSOR cursor)
  • ShowCursor2 (HCURSOR cursor, LPCTSTR Text)
  • ShowFont (HFONT Font)
  • ShowFont2 (HFONT Font, LPCTSTR Text)
  • ShowFont3 (LPCTSTR Sample, HFONT Font, LPCTSTR Text)
  • ShowImageList (HIMAGELIST List, int Index, UINT Flags)
  • ShowImageList2 (HIMAGELIST List, int Index, UINT Flags, LPCTSTR Text)
  • ShowRegion (HRGN Region)
  • ShowRegion2 (HRGN Region, LPCTSTR Text)
  • ShowRegion3 (HRGN Region, HBITMAP Bitmap, LPCTSTR Text)
  • ShowRegion4 (HRGN Region, HDC DC, LPCTSTR Text)

所有这些宏都返回一个 LRESULT 值,该值表示一个 Win32 错误代码。可能的返回码解释如下。

ShowBitmap()ShowDC()ShowGDIPlusBitmap() 函数将“按原样”显示图像。

要观察您可能正在处理的 Gdiplus::Graphics 对象,请使用一个 Image 创建它,并观察该 Image

Image bmp(width, height);
Graphics g(bmp);
g.DrawImage(Picture, 0, 0);
ShowGDIPlusBitmap(bmp); // take a peek at what is drawn.

ShowIcon()ShowCursor 函数将图标或光标显示为三部分的水平图像。最左边部分是 AND 掩码,中间是 XOR 掩码,最右边部分是绘制时实际出现的图标或光标。

Image Viewer showing a cursor by using the ShowIcon() function

显示光标的图像查看器应用程序

ShowImageList() 函数最初由 Jrgen Sigvardsson 编写,其工作方式略有不同,因为它需要三个参数。它们是图像列表的句柄、列表中图像的索引以及一个自定义的 ILD_* 显示标志。索引可以是 -1,也可以是图像列表的合法索引。指定 -1 作为索引将绘制整个图像列表。图像被绘制三次:顶部使用 ILD_NORMAL,中间使用 ILD_TRANSPARENT,底部使用自定义的 ILD_* 标志参数绘制。

通过 ShowRegion 函数(基于 WalderMort 提供的代码),可以在默认背景上以黑色显示 HRGN,或者如果提供了 HBITMAP 或 HDC 作为背景图像,则通过反转所提供 HRGN 内的背景图像像素来显示 HRGN。

Image Viewer showing an HRGN region by inverting the colours of a bitmap

图像查看器通过反转位图颜色来显示 HRGN 区域

这些函数的第二个版本接受一个指向描述性文本的 LPCTSTR 指针,该文本可以在稍后从图像查看器应用程序查看图像时访问。它将显示在子框架的状态栏中,也可以在属性对话框中看到。属性对话框还显示图像的像素尺寸、图像的位深度以及调用 Show* 宏的源文件和行号。

Image properties dialog

图像属性对话框

ShowGraphic() API 函数

ShowGraphic 函数是 2.2 版本中的新功能。它旨在取代所有先前列出的 Show* 函数。问题在于它使用了 __noop 关键字,因此在旧版本的 Visual C++ 中不起作用。ShowGraphic 函数需要 Visual C++ 7.0 或更高版本。ShowGraphic 函数的代码基于 Paul MclachlanLocation Trace 文章,最初由 Mor FTP 为此函数改编。ShowGraphic 的一个主要优点是,通过使用运算符重载,一个函数现在可以显示许多不同的图形对象。另一个主要优点是,现在可以使用 printf 风格的格式化来指定描述性文本。

各种重载列在这里。

  • LRESULT ShowGraphic(HBITMAP hBitmap, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HDC hDC, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HICON hIcon, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HCURSOR hCursor, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HFONT hFont, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(LPCTSTR Sample, HFONT hFont, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HIMAGELIST hList, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HRGN hRgn, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HRGN hRgn, HBITMAP hBitmap, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HRGN hRgn, HDC hDC, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(Gdiplus::Image Image, LPCTSTR Format = NULL, ...)

API 返回值

所有这些错误返回码都在 WinError.h 头文件中定义。如果图像查看器实用工具未被激活(见上文),所有 Show* 函数将返回零。如果图像查看器实用工具是活动的,那么这些是 Show* 函数可能返回的值。

  • ERROR_SUCCESS
    • 图形对象已成功发送到图像查看器应用程序。
  • ERROR_NOT_READY
    • 用于与图像查看器应用程序通信的隐藏窗口尚未准备好。最常见的原因是图像查看器应用程序没有运行。
  • ERROR_INVALID_HANDLE
    • 图形对象句柄为 NULL。
  • ERROR_INVALID_DATA
    • 仅限 HRGN 对象。HRGN 句柄有效,但区域本身为空。
  • ERROR_FUNCTION_FAILED
    • 函数内部发生了未指定的错误,因此无法将图形对象发送到图像查看器应用程序。
  • ERROR_TIMEOUT
    • 函数尝试将图形对象发送到图像查看器应用程序,但图像查看器应用程序响应时间过长。
  • ERROR_SHARING_PAUSED
    • 图像查看器应用程序处于暂停状态,此时不接收任何内容。
  • ERROR_NOT_ENOUGH_MEMORY
    • 图像查看器应用程序已用完其所有分配的内存。

如果您运行提供的演示应用程序,您需要先启动 ImageViewer.exe 程序,然后单步执行 ViewerDemoView::OnDraw() 函数。

我希望你们中的一些人会发现这个工具和我一样有用。

导航图像查看器应用程序

查看器应用程序在 2.0 版本中得到了极大的改进。新增的主要功能是历史记录功能以及将会话或单个图像保存到磁盘以便日后浏览或与他人共享的能力。借助历史记录功能,可以向前和向后浏览生成的图像,这样无需重新运行正在调试的应用程序即可查看和复查它们。图像查看器应用程序是作为 MFC MDI 应用程序构建的。每次调试应用程序的新实例时,都会在图像查看器中创建一个新的 MDI 文档。这使得比较不同运行变得容易。还可以为同一文档创建多个视图,以便并排比较连续的图像。

还可以将生成的图像保存到磁盘。整个历史文档可以保存到 *.ivd 文件(Image Viewer Data file)中,该文件可以重新加载到图像查看器中以供日后查看。或者,单个图像可以保存为磁盘上的图片文件。

支持的图片文件格式有:

  • 便携式网络图形 (*.png)。
  • Windows 位图 (*.bmp)。
  • 标签图像文件格式 (*.tiff)。
  • 图形交换格式 (*.gif)。
  • 联合图像专家组 (*.jpeg)。

此外,图像查看器可以读取但不能写入以下类型的文件:

  • Windows 图标 (*.ico)。
    • 仅读取第一个图像。不支持多图像图标。
  • Windows 元文件 (*.wmf)。
  • 增强型元文件 (*.emf)。

工具栏

工具栏上的每个按钮都有一个对应的菜单项和键盘快捷键。

图像接收控制

暂停。

  • 菜单:文件/暂停。
  • 键盘:<Pause>。

暂停图像接收。当图像查看器处于暂停状态时,它不会从任何其他应用程序接收任何图像。

保存和打开会话数据

保存会话文档。

  • 菜单:文件/另存为。
  • 键盘:<CTRL>+'S'。

将整个文档保存到一个 *.ivd 文件中。如果文件中有大量图像,文件可能会变得非常大,因为它被保存为一系列未压缩的 DIB。

打开会话文档。

  • 菜单:文件/打开。
  • 键盘:<CTRL>+'O'。

打开一个先前保存的 *.ivd 文件。

常规显示选项

总在最前。

  • 菜单:视图/总在最前。
  • 键盘:'T'。

使图像查看器应用程序保持在所有其他窗口的顶部,这样它就不会被其他进程遮挡。

背景颜色。

  • 菜单:视图/背景颜色。
  • 键盘:'B'。

弹出标准的选择颜色对话框,以选择用于填充图像透明部分以及填充视图中未被图像覆盖部分的背景颜色。

十六进制工具提示。

  • 菜单:视图/十六进制工具提示。
  • 键盘:'X'。

在十进制和十六进制显示之间切换工具提示窗口上的颜色值。

锁定显示。

  • 菜单:视图/锁定显示。
  • 键盘:'D'。

锁定当前正在查看的图像的显示。如果未设置此选项,则图像查看器接收到的最后一张图像将在接收时立即显示。

单个图像选项

另存为图片。

  • 菜单:图像/另存为图片。
  • 键盘:'S'。

将当前正在查看的图像作为图片文件保存在磁盘上。

属性。

  • 菜单:图像/属性。
  • 键盘:'P' 显示,<ESC> 隐藏。

切换属性对话框。属性对话框上显示的数据会随着当前查看的图像变化而更新。

删除图像。

  • 菜单:图像/删除。
  • 键盘:<DEL>。

弹出一个对话框,可以选择从会话文档中的图像中删除一个或一系列图像。默认设置是删除当前正在查看的图像。

图像历史选择选项

转到第一张图像。

  • 菜单:图像/第一张。
  • 键盘:Shift + '<'。
  • 鼠标:按下鼠标右键,然后向上移动鼠标。

转到上一张图像。

  • 菜单:图像/上一张。
  • 键盘:'<'。
  • 鼠标:按下鼠标右键,然后向左移动鼠标。

选择一张图像。

  • 菜单:图像/选择。
  • 键盘:'?'。

转到下一张图像。

  • 菜单:图像/下一张。
  • 键盘:'>'。
  • 鼠标:按下鼠标右键,然后向右移动鼠标。

转到最后一张图像。

  • 菜单:图像/最后一张。
  • 键盘:Shift + '>'。
  • 鼠标:按下鼠标右键,然后向下移动鼠标。

图像缩放选项

显示网格。

  • 菜单:缩放/网格。
  • 键盘:'G'。

在图像上绘制一个网格,勾勒出每个像素的轮廓。图像必须放大至少 200% 才能显示网格。

放大。

  • 菜单:缩放/放大。
  • 键盘:'+'。
  • 鼠标:<CTRL>+向上滚动鼠标滚轮。

缩小。

  • 菜单:缩放/缩小。
  • 键盘:'-'。
  • 鼠标:<CTRL>+向下滚动鼠标滚轮。

工具提示和滚动

鼠标光标下像素的坐标和 RGB 颜色会显示在一个跟随鼠标光标移动的工具提示上。控制工具提示最直接的方法是抓住鼠标并移动它。但对于更精细的控制,或者对于不喜欢使用鼠标的人,鼠标光标可以用键盘上的箭头键控制。箭头键的默认行为是首先将图像滚动一个像素,而鼠标光标保持在屏幕上的位置,直到图像无法再滚动为止。此时,鼠标光标将移动,直到碰到视图的边缘。要禁用滚动并改为移动鼠标光标,只需在按下箭头键的同时按住 SHIFT 键,或切换键盘上的 Scroll Lock 按钮。鼠标光标必须在视图上方才能生效,但只需按键盘上的 'C' 键即可将鼠标光标置于视图中心。

视图也可以使用 Home、End、PageUp 或 PageDown 按钮以及滚动鼠标滚轮来滚动。这些控件的标准行为是垂直滚动视图,但通过在同时使用这些控件时按住 SHIFT 键,视图将水平滚动。如果使用鼠标,可以通过按住鼠标左键并将鼠标光标移向视图边缘来滚动视图。单击鼠标中键或鼠标滚轮将启动平移功能。

内存管理

在下面的论坛中有人担心图像查看器是一个真正的内存消耗大户。因此,从 2.1 版本开始,现在可以限制查看器用于存储其接收图像的最大内存量。当没有打开子视图窗口时,默认菜单会有一个“设置/内存...”选项。如果选择该选项,您将得到一个对话框,允许您设置图像查看器将使用的最大内存量。您可以设置 100000 KB 到 1750000 KB 范围内的任何数量。

另一个为控制内存使用而增加的机制是增加了“暂停”命令和工具栏按钮。现在可以暂停图像查看器应用程序,使其不会从任何可能试图发送图像的其他应用程序接收图像。

为了让用户能够随时查看图像查看器应用程序正在使用多少内存,状态栏上增加了一个内存使用计量器。该计量器有正在使用的内存量的文本读出,还有一个图形化的“进度条”,显示已用可用内存的多少以及还剩多少可用内存。

内存使用计量器

当内存不足时,要释放内存,只需关闭一个文档窗口,或者使用“图像/删除”命令删除一堆您可能不再需要的旧图像。

状态栏

状态栏可用于提供有关图像查看器应用程序和当前正在查看的图像的信息。主状态栏有三个窗格。第一个是标准信息窗格,显示应用程序的当前状态,并显示有关当前选择的工具栏按钮和菜单项的有用提示。第二个是前面提到的内存使用计量器。第三个是滚动锁定指示器。

附加到子视图窗口的状态栏显示有关该视图中当前显示图像的信息。它有六个窗格,可以通过在“视图/指示器”菜单中选择它们来选择性地显示或隐藏。第一个窗格是文本窗格。它显示调用 Show* 函数时随图像提供的文本的第一行。接下来的窗格显示调用 Show* 函数的时间以及 Show* 函数所在的源文件、行和函数。最后一个窗格显示图像的尺寸(以像素为单位)。

图像查看器的状态栏

愿望清单

我想为这个应用程序添加几项功能。主要是扩展对 GDI+ API 的支持。目前只支持 Gdiplus::Image。我还想增加对其他 GDI 对象(如 HPENHBRUSH 等)的支持。我还想编写一个安装/卸载程序,能够正确地为各种版本的 Visual Studio 设置和注册文件。

如果您决定为这个应用程序实现任何附加功能,请随时在下面的论坛中发布代码,或通过电子邮件发送给我。如果我喜欢它们,我甚至可能会在未来的版本中包含它们。

免责声明

版权所有 (c) 2001-2006, PJ Arends

本软件以免费软件形式发布,并按“原样”提供,不附带任何明示或暗示的保证,包括但不限于对适销性和特定用途适用性的暗示保证。

您可以以任何您希望的方式使用此代码。此代码可以通过任何方式重新分发,只要不出于盈利目的进行销售,并且包含此声明和作者姓名。任何非原作者所做的修改都应明确标记,以消除原始版本与任何其他版本之间的混淆。

如果发现并修复了任何错误,最好能给作者发个便条,说明问题和修复方法。

致谢与鸣谢

更新

  • 2002年1月31日
    • 修复了 Melwyn 报告的 W2K 错误。
  • 2004年4月11日
    • 添加了 ShowIcon() 函数。
  • 2004年8月31日
    • 添加了 ShowGDIPlusBitmap() 函数。
    • 添加了 ShowImageList() 函数。(感谢 Jrgen)
  • 2006年9月12日
    • 发布了 2.0 版本。
  • 2006年11月13日 - 2.1 版本
    • 添加了 ShowRegion 函数。(感谢 WalderMort)
    • 添加了内存管理和暂停功能。
    • 各种其他代码清理和增强。
  • 2006年12月16日 - 2.2 版本
    • 添加了 ShowFont 函数。
    • 添加了 ShowGraphic 函数。(感谢 Mor FTP。)
    • 更新了图像查看器的子状态栏。现在可以选择显示关于当前图像的更多信息。
    • 更新了图像查看器处理区域的方式。工具提示现在显示区域的坐标,区域的边界矩形坐标现在显示在状态栏上。
    • Show* 函数添加了错误返回码。
    • 更改了“转到第一张图像”和“转到最后一张图像”命令的键盘快捷键。
    • 在文章文本中添加了愿望清单和免责声明。
  • 2006年12月23日 - 2.2.1 版本
    • 修复了 Owen Lawrence 报告的错误。
  • 2006年3月5日 - 2.3 版本
    • 增加了直接加载某些图形文件的支持。图像查看器应用程序现在可以用作独立的图片查看应用程序。
    • 重写了绘图代码,这样我们现在可以放大大型图像而不会耗尽系统资源。
    • 为文章添加了目录。
    • 各种其他小的修复和调整。
© . All rights reserved.