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

ImageFan

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (30投票s)

2010 年 2 月 24 日

CPOL

6分钟阅读

viewsIcon

78115

downloadIcon

5558

.NET 2.0 的轻量级图像查看器,支持多核处理

引言

ImageFan 是一个轻量级的 .NET 2.0 图像查看器,支持多核处理。

背景

我一直希望能够利用 .NET 的能力来创建一个图像查看器,为现有的 C/C++ 解决方案提供一个托管(可能因为 Mono 而可移植)的替代方案。此外,缺乏 64 位图像查看器也促使我寻求一个 .NET 解决方案,该方案在硬件和软件平台允许的情况下,可以自动作为 64 位应用程序运行。

视觉布局和功能

该应用程序的设计风格传统,与当代的图像查看器相似,如下所示:

  • 窗口左侧有一个驱动器列表和相应的目录树。
  • 右侧有一个缩略图列表,显示所选驱动器和目录中图像的缩略图。

选择一个驱动器会刷新目录列表,并显示驱动器根目录中图像的缩略图。选择一个特定目录会将缩略图列表填充为相应的缩略图。可以使用箭头键和滚动条浏览缩略图列表。

当鼠标左键单击缩略图或按下 Enter 键时,将打开一个新窗口,其中包含全尺寸图像。如果图像的至少一个维度大于相应的屏幕尺寸维度,则该图像可以滚动。用户可以使用此窗口通过空格键、退格键和箭头键来遍历图像列表。可以通过按 Esc 键或窗口上的关闭按钮来关闭窗口。

如果再次单击图像窗口或按下 Enter 键,则会将图像设置为全屏视图,并在必要时调整其大小以适应屏幕。在全屏模式下,可以使用空格键、退格键、箭头键和鼠标滚轮来导航缩略图列表。用户可以通过按 Esc 键或鼠标左键退出此模式。

实现挑战和限制

项目结构如下图所示。我将依次解释每个相关的源代码构件。

类 TasksDispatcher 

这个类是一个通用的任务调度器,它将任务数组划分为可用处理器核心的数量。在之前的版本中,该类使用原始线程。在此版本中,它依赖于 .NET 的 ThreadPool 类,因此依赖于线程池中的线程,最大限度地减少了线程创建和销毁的成本。

对于当前问题,我使用任务调度器类来划分(按索引)要异步显示的图像缩略图集合,当用户选择一个目录时。

using System;
using System.Threading;

namespace ImageFan.Auxiliary
{
    internal class TasksDispatcher
    {
        public TasksDispatcher(WaitCallback globalTask, WaitCallback individualTask, int tasksCount)
        {
            _globalTask = globalTask;
            _individualTask = individualTask;
            _tasksCount = tasksCount;

            _isStopped = true;
        }

        public void Start()
        {
            _dispatcherIsActive = true;
            
            ThreadPool.QueueUserWorkItem(WorkerThreadLoopMethod);
        }

        public void Stop()
        {
            _dispatcherIsActive = false;
        }

        public bool IsStopped
        {
            get { return _isStopped; }
        }


        #region Private

        private static readonly int ProcessorCount;
        private static AutoResetEvent[] IndividualTaskEvents;

        private WaitCallback _globalTask;
        private WaitCallback _individualTask;
        private int _tasksCount;

        private volatile bool _dispatcherIsActive;
        private volatile bool _isStopped;

        private void WorkerThreadLoopMethod(object state)
        {
            try
            {
                _isStopped = false;
                
                for (var i = 0; (i < _tasksCount) && (_dispatcherIsActive); i += ProcessorCount)
                {
                    int j;

                    for (j = 0; (j < ProcessorCount) && (i + j < _tasksCount) && (_dispatcherIsActive); j++)
                        _globalTask(i + j);

                    for (j = 0; (j < ProcessorCount) && (i + j < _tasksCount) && (_dispatcherIsActive); j++)
                        ThreadPool.QueueUserWorkItem(IndividualTaskWrapper, new TaskParameter(i + j, j));

                    for (j = 0; (j < ProcessorCount) && (i + j < _tasksCount) && (_dispatcherIsActive); j++)
                        IndividualTaskEvents[j].Set();
                }
            }
            catch
            {
            }
            finally
            {
                _isStopped = true;
            }
        }

        private void IndividualTaskWrapper(object state)
        {
            try
            {
                TaskParameter taskParam = ((TaskParameter)state);

                IndividualTaskEvents[taskParam.ThreadIndex].WaitOne();
                _individualTask(taskParam.MainIndex);
            }
            catch
            {
            }
        }

        #endregion


        static TasksDispatcher()
        {
            ProcessorCount = Environment.ProcessorCount;

            IndividualTaskEvents = new AutoResetEvent[ProcessorCount];
            for (var i = 0; i < ProcessorCount; i++)
                IndividualTaskEvents[i] = new AutoResetEvent(false);
        }
    }
}

类 FolderTreeView

此类是 Windows 窗体自定义控件,扩展了 TreeView 控件。它以树状方式显示所选驱动器上的文件夹(目录),并在选择目录节点时,触发在 ThumbnailsSequence 控件中显示缩略图。

类 ThumbnailBox

此类型是一个 Windows 窗体自定义控件,继承自 UserControl 类。它是一个可变大小的控件,显示一个图像缩略图框,其中包含图像缩略图本身,并装饰有图像文件名。其最大尺寸(宽度或高度)会缩放到 ThumbnailSize(200 像素),而另一个尺寸则按比例缩放。

类 ThumbnailsSequence

ThumbnailsSequence 类派生自 FlowLayout 面板,并用作磁盘上所选目录生成的缩略图的容器。

类 ImageForm

ImageForm 是一个 Windows 窗体,当用户单击特定图像缩略图、在目录内的图像上进行键盘导航时,或在退出全屏模式后,会以对话框的形式显示。该窗体保留图像大小,并在图像超出屏幕大小时启用滚动。

类 FullScreenImage

此类是一个 Windows 窗体,以对话框形式显示,没有窗体边框,占用全屏尺寸并具有黑色背景。因此,它给人一种不寻常的 GUI 伪影的视觉错觉,具有全屏模式。它还会调整图像大小(如果大于可用全屏尺寸),同时保持初始纵横比。

类 ImageFile

ImageFile 是一个享元模式类,将图像缩略图存储为其内在状态,并将全尺寸图像作为其外在状态,仅在需要时检索。

类 ImageFolder

此类提取并管理给定文件夹(目录)中的图像文件。

类 ImageResizer

此类型具有两个操作:调整从文件提取的图像的大小(用于生成缩略图)和调整内存中的图像的大小(用于全屏模式)。

类 GlobalData

此类包含对资源图像 LoadingImageInvalidImage 以及它们各自缩略图的引用。

学到的教训

尽管这个图像查看器是一个托管应用程序,但在浏览或查看速度方面(除了特定优化外),与 IrfanViewXnViewAcdSee 等原生可执行文件解决方案相比,没有任何差异。这是因为 .NET 的 System.DrawingSystem.Windows.Forms 类是 WinAPI 功能相当紧密的包装器。

Bitmap 类继承的 Image 类实现了 IDisposable 接口,使得享元设计模式的实现变得直接,因为能够以确定性的方式管理图像内存占用。

64 位操作系统的普遍存在使得托管编程运行时真正 shines。这是因为用托管语言(如 .NET CLS 兼容语言)编写的应用程序本质上支持 32 位到 64 位切换,使用相同的二进制包,同时提供运行平台的全部优势。

源代码和应用程序下载

ImageFan 应用程序(一个 Google Code 项目)的完整源代码可以通过 此处 访问。如果只对二进制文件感兴趣,可以从 此链接 下载。

我非常欢迎对这个 ImageFan 开源 (GPL v3) 项目 的贡献和反馈。

参考文献

  • [1] Microsoft Developer Network (MSDN) 页面

历史

  • 版本 0.1 - 初次提交 - 2010/02/24
  • 版本 0.2 - 在文章开头添加了下载链接 - 2010/02/28
  • 版本 0.3 - 代码优化和错误修复 - 2010/04/18
  • 版本 0.4 - 更新了内容、源代码和二进制文件 - 2011/09/21
  • 版本 0.5 - 重构代码并进行大量错误修复 - 2012/04/09
  • 版本 0.6 - 多项代码更改和增强。从文章中移除了部分代码示例,因为它们已变得冗长且令人分心。清理了文章文本 - 2013/01/04
  • 版本 0.7 - 一些错误修复。使缩略图框可变大小,以增加屏幕上的缩略图数量 - 2013/04/09
  • 版本 0.8 - 对代码和文本一致性进行了小的改进 - 2015/02/25
© . All rights reserved.