Click here to Skip to main content
Licence CPOL
First Posted 24 Feb 2007
Views 49,110
Downloads 901
Bookmarked 49 times

A C# based thumbnail viewer

By | 18 May 2007 | Article
A C# based thumbnail viewer employing a BackgroundWorker to load images in the background.

JThumbnailView Demo project

Introduction

Many a times we come across situations where it is required to show images from a directory as thumbnails. This control JThumnailView does exactly that. The additional feature of this control is that it uses a background worker to load images asynchronously.

Background

It all started when I wanted to send some photos back home electronically. Of course, I could do that using e-mails; however, when doing so, it would mostly be zipped and sent. When I saw my parents struggling to keep track of where they saved the photos for later viewing, I realised that I needed to provide them something which could be controlled by me. Hence, I started developing an application which once installed on a machine will serve as an automatic picture downloader and a basic viewer. Thus, I was faced with the following challenges:

  1. How to do an automatic download? My answer came in the form of the edtFTPnet component, with which I could go and download file(s) from an FTP server. However, this posed another problem: every time I want to send new photos, I needed some mechanism which would transparently do it without any manual intervention. That is when I decided to use an XML file which the application would read and perform the necessary action. However, once I started developing the XML file, I wanted to encrypt it and give a different extension. Hence, I used a DESCryptoServiceProvider to perform the encryption/decryption for the file. Now, all I have to do is send my file (which has a *.pfi extension) and give a password. When this file is double clicked, it will ask for a password and it will start downloading the photos automatically from my FTP site.
  2. The second challenge for me was to provide a simple photo viewer in the same application so that the user need not worry about where the photos are stored. For this, I needed two components: an Explorer-like folder viewer and a thumbnail viewer. That is when I got the WindowsExplorer component written by Rajesh Lal. Though I had to make a little modifications to suit my requirements, it saved me a lot of time.
  3. The only thing remaining was a thumbnail viewer. I searched for a good one, but most of them were for ASP.NET. Finally, I saw one, but again it was based on VC++. That is when I decided to write one. I made it a control so that others could re-use it. This article describes the JThumnailView component I created for this purpose. For those who want the full version of the application, please contact me by email. I will be more than happy to provide it (though it is still in the beta phase!!!).

Using the Code

The component is very simple to understand. It has been derived from the standard ListView control so that I need not worry about things like scrolling, sorting etc. :).

The following are the main properties:

public int ThumbNailSize; //default value: 95

By default, it has a value of 95 (Windows Explorer seemed to use this size, so I made it the default).

public int ThumbBorderColor; //default value: Color.Wheat

Set this if you want the thumbnails to have a different border.

public string FolderName; //default value: Application folder

This is the directory from which the thumbnails are to be loaded. The component has another property CanLoad which should be set to true to load the images. This should be set to true on the constructor of the form.

One of the main problems with most of the thumbnail viewers is that if the number of files in a directory is high, then the viewer takes a lot of time to load. To avoid this, the technique I am using is to create a default thumbnail which is just a square of the thumbnail size and set this as the image-index for all the items. This will give the user an impression that the thumbnails have been loaded. Then the actual thumbnails are loaded in the background using a BackgroundWorker.

private BackgroundWorker myWorker = new BackgroundWorker();

The loading of items is handled in the method ReloadItems().

private void ReLoadItems() 
{ 
    BeginUpdate(); 
    Items.Clear(); 
    LargeImageList.Images.Clear(); 
    AddDefaultThumb(); 
    
    string strFilter = "*.jpg;*.png;*.gif;*.bmp"; 
    List fileList = new List(); 
    string[] arExtensions = strFilter.Split(';'); 
    
    foreach (string filter in arExtensions) 
    { 
        string[] strFiles = Directory.GetFiles(folderName, filter); 
        fileList.AddRange(strFiles); 
        for (int i = 0; i < strFiles.Length; i++) 
        { 
            FileInfo fiTemp = new FileInfo(strFiles[i]); 
            Items.Add(fiTemp.Name, 0).Tag = strFiles[i]; } 
        } 
        
        fileList.Sort(); 
        EndUpdate(); 
        if (myWorker != null) { myWorker.RunWorkerAsync(fileList); } 
    }
}

The AddDefaultThumb() method creates a default thumbnail as mentioned above. The actual thumbnails are drawn in the DoWork() event of the BackgroundWorker. The thumbnails are drawn using the usual graphic methods.

Points of Interest

The use of the BackgroundWorker definitely improved the efficiency of the viewer considerably. Another interesting thing was the use of PixelOffSetMode and InterpolationMode of the Graphics object. When I drew the thumbnails first, I could not match the clarity of the images in the Windows Explorer thumbnail. That is when I tried out the various PixelOffSetModes and the InterpolationModes. I achieved the desired result with the following combination:

PixelOffsetMode = PixelOffsetMode.None;

InterpolationMode = InterpolationMode.HighQualityBicubic;

History

Version 1.1

Thanks for all the valuable comments, I have modified the component to include some more checks :). I have also modified the demo to include a minimal picture viewer. Thanks once again to all of you, especially Michael for his special interest and feedback. I still have not really tested dynamic dispose and creation, and hence not sure whether the problem is still there.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sreejai R. Kurup

Web Developer

United Arab Emirates United Arab Emirates

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralMy vote of 5 Pinmembermanoj kumar choubey20:56 26 Feb '12  
GeneralNice, but... PinmemberDoncp11:30 10 Jan '11  
GeneralAbout the source code PinmemberCisily23:30 12 May '09  
GeneralStill inconsistency with the thumbnail and the filename Pinmembermartinmoesbypetersen0:24 10 Jan '09  
GeneralThumbnail Generation PinmemberMember 352586322:09 17 Dec '08  
GeneralMy vote of 1 PinmemberWertugo55521:53 8 Dec '08  
GeneralGreat Work!! PinmemberRichard Blythe19:11 10 Oct '08  
Generalfull version of the application PinmemberMember 368254819:55 3 Aug '08  
GeneralError Pinmembermfmanca9:57 30 Oct '07  
GeneralRe: Error PinmemberEdward Ceballos22:41 29 May '08  
Generalgetting filename of selected items PinmemberElsys18:05 19 Oct '07  
GeneralStop BackGroundWorker Pinmemberfracasado7:56 31 Aug '07  
GeneralRe: Stop BackGroundWorker PinmemberSreejai R. Kurup18:30 31 Aug '07  
Questioncan this be modded to work for mpeg thumbnails ? PinmemberUltraWhack7:09 31 May '07  
AnswerRe: can this be modded to work for mpeg thumbnails ? PinmemberSreejai R. Kurup18:03 31 May '07  
GeneralRe: can this be modded to work for mpeg thumbnails ? PinmemberUltraWhack2:22 1 Jun '07  
GeneralBug: Thumbnail image inconsistency with real image Pinmembermpgjunky6:06 17 May '07  
Hi,
 
First of all, thanks for the control, great job. I wanted to write something identical for a project, but you've saved me the hassle. Smile | :)
 
However, unless you are already aware of it, you have a bug in that thumbnails displayed do not correspond to the real images (including in your demo program). To clarify, your thumbnail showed image from b.jpg, but the tag was a.jpg (I hope I have explained myself correctly Smile | :) ).
 
The problem is with:
 

foreach (string filter in arExtensions)
{
string[] strFiles = Directory.GetFiles(folderName, filter);
fileList.AddRange(strFiles);
for (int i = 0; i < strFiles.Length; i++)
{
FileInfo fiTemp = new FileInfo(strFiles[i]);
Items.Add(fiTemp.Name, 0).Tag = strFiles[i];
}
}
 
fileList.Sort();
EndUpdate();
if (myWorker != null)
{
myWorker.RunWorkerAsync(fileList);
}

 
...you are adding the items from strFile[] which is in a certain order, but the thumnails are generated using fileList which is a sorted list.
 
The correct logic would be something like:
 

List fileList = new List();
string[] arExtensions = strFilter.Split(';');
 
foreach (string filter in arExtensions)
{
string[] strFiles = Directory.GetFiles(folderName, filter);
fileList.AddRange(strFiles);
}
 
fileList.Sort();
 
for (int i = 0; i < fileList.Count; i++)
{
FileInfo fiTemp = new FileInfo(fileList[i]);
Items.Add(fiTemp.Name, 0).Tag = fileList[i];
}
 
EndUpdate();

 
...basically get files, add files to the List, sort the List, and then add the Items based on the order of the [sorted] List. This will ensure the correct thumbnail will shown for the correct tag name (or filename).
 
(PS: The above fix may not be necessarily the most efficient, but it works Smile | :) ).
(PS: I have added a new method LoadItems(string[] _filelist) in case you (or anyone else is interested) - which creates thimbnails from an array of filenames).
 
Cheers,
Michael.
GeneralCrashes if you make it start loading new thumbnails before it's finished Pinmembermrhaan7:40 11 Apr '07  
GeneralBackgroundWorker PinmemberBushRob12:11 27 Mar '07  
GeneralRe: BackgroundWorker PinmemberSreejai R. Kurup19:48 4 Apr '07  
GeneralRe: BackgroundWorker Pinmemberwmhp112:15 20 Apr '07  
AnswerRe: BackgroundWorker [modified] Pinmembermpgjunky6:18 17 May '07  
GeneralNo source code Pinmembercykophysh3921:53 24 Feb '07  
GeneralRe: No source code PinmemberSreejai R. Kurup0:01 25 Feb '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120529.1 | Last Updated 19 May 2007
Article Copyright 2007 by Sreejai R. Kurup
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid