ClipboardImageArchiver is a utility that archives clipboard images. It saves images from the clipboard to one single destination freeing you from remembering where exactly you saved your images. You can retrieve these images as a single Zip file or to a directory. ClipboardImageArchiver also gives you the option of saving images in different formats. ClipboardImageArchiver uses the open source SharpZip compression library. ClipboardImageArchiver overcomes the problem of 'appending to Zip' files using a combination of binary serialization and stream compression. This article mainly discusses this method used by ClipboardImageArchiver and its merits/demerits.
Screenshot of the main application
All the user has to do is to ‘copy’ an image and right click the ClipboardImageArchiver icon in the task bar, and select ‘paste’ from the menu. A small popup appears at the right corner of the screen giving information on the size, format and name of the saved image. The user can also choose a format by selecting ‘Format’ from the menu and clicking the desired format. Currently seven formats are supported: JPEG, Bitmap, GIF, PNG, WMF, EMF and TIFF. By default, JPEG is selected.
ClipboardImageArchiver minimized to task bar. Menu is shown on right clicking the icon (left most in task bar).
Success message on saving of an image from clipboard.
All the saved images can be retrieved simply by clicking ‘Export’ in the main screen. There are two options, one to export as a single file or to export as individual files to a directory. In both cases, the formats of individual files are retained.
The problem of ‘appending’ to a Zip File
There is no way we can directly append an entry to an existing Zip archive. It is unlike appending text to text file. It is worth understanding here that any data appended to a Zip file causes changes throughout the Zip file. I mean, it does not cause localized changes.
So this means every time I have to add something to, say a file named images.zip, these are the steps I need to perform:
- Initialize a new
ZipOutputStream object. Copy items from old Zip file to new Zip file as Zip entries.
- Create and add a new Zip entry for the new file to be added.
- Call compress method on
ZipOutputStreamObject, that saves it to a temp.zip file.
- Now delete images.zip and replace it with temp.zip.
This is the exact sequence of events that takes place, when you add a new file to a Zip archive. This has the following obvious disadvantages:
- Every time you add a new entry, we have to create a temporary Zip. Copy all entries from the old file to it.
- If the Zip archives are very large, they will take up a lot of disk space and memory resources. This is very undesirable for a utility like ClipboardImageArchiver.
- Also as the size of the images.zip file increases, it takes more and more time to add new entries. Very undesirable!!
Overcoming the problem
To overcome this problem, we use a combination of serialization and stream compression. First, I created a class called ‘
ZipImageObject’ that holds compressed data of the image in the following format:
private long _length;
The length in bytes of the actual uncompressed image.
private byte  _imgData;
GZipped (binary) image byte stream. This is where the compression is done. The binary image is compressed using GZip algorithm from the library and the resulting data is stored as a byte stream.
private short _imgFormat;
Integer indicating format of image.
private string _fileName;
Name of image [GUID].
When the user ‘pastes’ an image into the Zip clip, the following sequence of events occurs:
Diagram showing internal working of ClipboardImageArchiver.
The code below illustrates how a BMP file is transformed to a
ZipImageObject using GZip compression. This
ZipImageObject is serialized and stored into a data.dat file. The code is pretty straightforward and self-explanatory:
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.Write(bmpData, 0, bmpData.Length);
ZipImageObject zipImg = new ZipImageObject();
zipImg.Filename = bmpFilename;
zipImg.ImgData = ms.ToArray();
zipImg.Length = fsbmpFile.Length;
One thing must be noted here that, we may not get an optimum compression here. I mean a file containing ten
ZipImageObjects may occupy more space than a single Zip file containing all the images. This is a disadvantage of this method. Even then the difference in their sizes shouldn’t be much. When the user clicks ‘Export’, all the serialized
ZipImageObjects are exported to a Zip archive. The complete code for this application can be downloaded from the above link.
Important: To compile the code, you will have to add reference to ICSharpCode.SharpZipLib.dll in the IDE.
ClipboardImageArchiver demonstrates a way of avoiding frequent read/writes to disk while working with Zip compression. It uses a combination of stream compression and serialization for the same. The technique is very useful when dealing with large data. Also it is a very useful and handy utility to save images while browsing the web.
Hope you found this article useful. Any comments and criticism is always welcomed.