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

剪贴板图像存档器

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (6投票s)

2005年5月23日

4分钟阅读

viewsIcon

45794

downloadIcon

733

ClipboardImageArchiver 使用的方法 - 优点和缺点。

引言

ClipboardImageArchiver 是一个存档剪贴板图像的实用工具。它将剪贴板中的图像保存到一个单一的目的地,让您不必费心记住您具体将图像保存在哪里。您可以将这些图像作为单个 zip 文件或提取到某个目录中。ClipboardImageArchiver 还提供将图像保存为不同格式的选项。ClipboardImageArchiver 使用开源的 SharpZip 压缩库。ClipboardImageArchiver 结合了二进制序列化和流压缩来克服“追加到 zip”文件的难题。本文主要讨论 ClipboardImageArchiver 使用的这种方法及其优缺点。

主应用程序的屏幕截图

用户只需“复制”一张图像,然后在任务栏上右键单击 ClipboardImageArchiver 图标,然后从菜单中选择“粘贴”。屏幕右角会弹出一个小弹出窗口,提供有关已保存图像的大小、格式和名称的信息。用户还可以通过从菜单中选择“格式”并单击所需的格式来选择格式。目前支持七种格式:JPEG、Bitmap、GIF、PNG、WMF、EMF 和 TIFF。默认情况下选择 JPEG。

ClipboardImageArchiver 最小化到任务栏。通过右键单击图标(任务栏中最左边的图标)显示菜单

保存剪贴板图像后的成功消息

所有已保存的图像都可以通过单击主屏幕上的“导出”来检索。有两种选项,一种导出为单个文件,另一种导出为目录中的单个文件。在这两种情况下,都保留了单个文件的格式。

“追加”到 Zip 文件的难题

无法直接将条目追加到现有的 zip 存档。这不像向文本文件追加文本。值得在此理解的是,任何追加到 zip 文件的内容都会导致整个 zip 文件发生更改。我的意思是,它不会导致局部更改。

所以这意味着,每次我需要向例如名为 images.zip 的文件添加内容时,我需要执行以下步骤:

  1. 初始化一个新的 ZipOutputStream 对象。将旧 zip 文件中的项复制到新 zip 文件中作为 zip 条目。
  2. 创建并添加一个新 zip 条目,用于要添加的新文件。
  3. ZipOutputStreamObject 调用 compress 方法,将其保存到 temp.zip 文件。
  4. 现在删除 images.zip 并用 temp.zip 替换它。

这就是向 zip 存档添加新文件时发生的事件的确切顺序。这具有以下明显的缺点:

  1. 每次添加新条目时,我们都必须创建一个临时 zip。将所有条目从旧文件复制到其中。
  2. 如果 zip 存档非常大,它们将占用大量磁盘空间和内存资源。这对于 ClipboardImageArchiver 这样的实用工具来说是非常不可取的。
  3. 此外,随着 images.zip 文件大小的增加,添加新条目的时间会越来越长。非常不可取!

克服难题

为了克服这个问题,我们结合使用了序列化和流压缩。首先,我创建了一个名为 ‘ZipImageObject’ 的类,它以以下格式保存图像的压缩数据:

ZipImageObject 类

[Serializable]

  • private long _length;

    实际未压缩图像的字节长度

  • private byte [] _imgData;

    GZipped(二进制)图像字节流。这是进行压缩的地方。使用库中的 GZip 算法压缩二进制图像,并将生成的数据存储为字节流。

  • private short _imgFormat;

    指示图像格式的整数

  • private string _fileName;

    图像名称 [GUID]

当用户将图像“粘贴”到 zip 剪贴板时,会发生以下事件序列:

显示 ClipboardImageArchiver 内部工作原理的图表。

下面的代码说明了如何使用 GZip 压缩将 BMP 文件转换为 ZipImageObject。此 ZipImageObject 被序列化并存储到 data.dat 文件中。代码非常直接且不言自明。

public ZipImageObject CompressFile(string bmpFilename, short formatIndicator)
{
    FileStream fsbmpFile = new FileStream(bmpFilename, FileMode.Open);
    MemoryStream ms = new MemoryStream(Convert.ToInt32(fsbmpFile.Length));
    GZipOutputStream gzipOutput = new GZipOutputStream(ms);

    Byte[] bmpData = new Byte[Convert.ToInt32(fsbmpFile.Length)];
    fsbmpFile.Read(bmpData, 0, Convert.ToInt32(fsbmpFile.Length));

     gzipOutput.SetLevel(9);
     gzipOutput.Write(bmpData, 0, bmpData.Length);
     gzipOutput.Close();

     ZipImageObject zipImg = new ZipImageObject();
     zipImg.Filename = bmpFilename;
     zipImg.ImgData = ms.ToArray();
     zipImg.Length = fsbmpFile.Length;
     zipImg.ImgFormat =formatIndicator;

     fsbmpFile.Close();
     ms.Close();

     return zipImg;
}

这里需要注意的一点是,我们可能无法获得最佳压缩效果。我的意思是,包含十个 ZipImageObject 的文件可能比包含所有图像的单个 zip 文件占用更多空间。这是此方法的缺点。即便如此,它们的大小差异应该不会太大。当用户单击“导出”时,所有序列化的 ZipImageObject 都将导出到 zip 存档。此应用程序的完整代码可以从上面的链接下载。

重要:要编译代码,您必须在 IDE 中添加对 ICSharpCode.SharpZipLib.dll 的引用。

结论

ClipboardImageArchiver 展示了一种避免在处理 zip 压缩时频繁读写磁盘的方法。它为此结合使用了流压缩和序列化。该技术在处理大量数据时非常有用。此外,它是一个非常有用且便捷的实用工具,可以在浏览网页时保存图像。

希望您发现本文有用。任何评论和批评都欢迎。

历史

  • 2005 年 5 月 23 日:初始版本

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.