Click here to Skip to main content
11,709,536 members (51,431 online)
Click here to Skip to main content

WPF Filename To Icon Converter

, 30 Jan 2009 LGPL3 71.2K 2.8K 70
Rate this:
Please Sign up or sign in to vote.
This article describes FileToIconConverter, which is a MultiBinding Converter that can retrieve an Icon from system based on a filename(exist or not) and size.
mainScreen4.jpg

Introduction

This article describes FileToIconConverter, which is a MultiBinding Converter that can retrieve an Icon from system based on a filename (exist or not) and size.

Background

I am working on a file explorer, which shows a file list, inside the filelist, which requires to place a file icon next to each file in a folder.

In my first implementation, I added an Icon property in the data model of the file, it works fine.  When I implements the Icon View, I added a Large Icon property, then I added Thumbnail property for the Thumbnail view support.

This implementation has a number of problems:

  • Three Bitmaps (Icon, LargeIcon, Thumbnail), five if we include ExtraLarge and Jumbo in the Datamodel. They are usually duplicated (e.g. folder with JPGs), and unused (who will change views regularly anyway).
  • The code that is not related to the DataModel shouldn't be placed there.
  • Icon resize (like the slidebar in Vista Explorer) becomes very difficult, as there are 3-5 properties to bind with.

So I changed my design. I believe a converter with cache is best suited for this purpose.

  • Icons are cached in a dictionary, file with same extension occupied only one copy of memory.
  • Load on demand (e.g. if the view needs an Icon, then load Icon only).
  • Reusable, coder just needs to bind filename and size

Thumbnails are loaded in separate thread (no longer jam the UI). Jumbo icon is shown before the thumbnail is loaded.

mainScreen3.jpg

How to Use? 

The converter is a MultiBinding Converter, which takes 2 parameters, filename and size:

  • Filename need not necessarily exist (e.g. abc.txt works)
  • Size determines which icon to obtain (Optional)
    • <= 16 - Small
    • <= 32 - Large
    • <= 48 - Extra Large
    • <= 100 - Jumbo
    • Otherwise, Thumbnail if it is an image, Jumbo if it is not an image. 
<t:FileToIconConverter x:Name="converter" />
<Slider x:Name="slider" ... />
<TextBlock x:Name="fileName" ... />
<Image Height="{Binding ElementName=slider, Path=Value}" 
       Width="{Binding ActualHeight}" Stretch="Uniform">
    <Image.Source>
        <MultiBinding Converter="{StaticResource converter}">
            <Binding ElementName="fileName" Path="Text"/> <!-- FileName -->
            <Binding ElementName="slider" Path="Value" /> 
                            <!-- Size, use DefaultSize if not specified --> 
        </MultiBinding >
    </Image.Source>
</Image> 

How It Works?

MultiBinding Converter is similar to the normal Binding IValueConverter except it takes multiple value to convert, the Convert is as shown below:

public object Convert(object[] values, Type targetType, 
   object parameter, CultureInfo culture)
{
    int size = defaultSize;
    if (values.Length > 1 && values[1] is double)
      size = (int)(float)(double)values[1];
            
    if (values[0] is string)
      return imageDic[getIconKey(values[0] as string, size)];
    else return imageDic[getIconKey("", size)];
}
  • parameter 2 is converted to a local variable named size.
  • parameter 1 is converted to a Icon in imageDic with a key (getIconKey() method, see below). 

Icons are retrieved based on Size and Extensions

  • Thumbnail
    • Image - Return WritableBitmap (new in .NET 3.5), which acts like BitmapImage but allows change after initialization.
    • Otherwise - treat as Icon
  • Jumbo / ExtraLarge
  • Small / Large
    • Load using SHGetFileInfo (Win32 API) directly. I try to avoid SystemImageList because it has its own cache system which will cause some overhead.

There are two caches, iconCache and thumbnailCache, all Icons and thumbnail are stored in cache.

  • iconCache is static, for small - Jumbo Icons, common for all FileToIconConverter.
  • thumbnailCache is instanced, for thumbnail, you can call ClearInstanceCache() method to clear this cache.
  • addToDic() method will add the Icon or Thumbnail (from getImage()) to its cache
  • returnKey() method will return a key for dictionary based on fileName and size,
    • e.g. (".txt+L" for Large Text Icon, ".jpg+S" for Small JPEG icon)
  • loadBitmap() method takes a Bitmap and return a BitmapSource. It's actually calling Imaging.CreateBitmapSourceFromHBitmap() method, and is required because Image UIelement does not take a bitmap directly.

getImage() method retrieves Icon and Thumbnail, its thumbnail loading code looks like below:

//Load as jumbo icon first.                         
WriteableBitmap bitmap = new WriteableBitmap
		(addToDic(fileName, IconSize.jumbo) as BitmapSource);
ThreadPool.QueueUserWorkItem(new WaitCallback(PollThumbnailCallback), 
	new thumbnailInfo(bitmap, fileName));
return bitmap;

The code will try to load the jumbo icon first, which is usually cached already, and much faster to load not cache, then when the processor is free, it will call PollThumbnailCallback() in background thread. This implementation will prevent UI thread hogging problem.

PollThumbnailCallback() method is not too complicated. It actually gets and resizes the thumbnail bitmap (line 4-8), turns it to BitmapSource (Line 9-C), and writes it to the WriteableBitmap obtained (Line 6, D-Q). Line M to Line Q is executed in UI thread, so the only work that is required to process the writeBitmap is placed there.

1) private void PollThumbnailCallback(object state)
2) {
3)   //Non UIThread
4)   thumbnailInfo input = state as thumbnailInfo;
5)   string fileName = input.fullPath;
6)   WriteableBitmap writeBitmap = input.bitmap;

7)   Bitmap origBitmap = new Bitmap(fileName);
8)   Bitmap inputBitmap = resizeImage(origBitmap, new System.Drawing.Size(256, 256));
9)   BitmapSource inputBitmapSource = 
	Imaging.CreateBitmapSourceFromHBitmap(inputBitmap.GetHbitmap(),
A)   IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
B)   origBitmap.Dispose();
C)   inputBitmap.Dispose();

D)   int width = inputBitmapSource.PixelWidth;
E)   int height = inputBitmapSource.PixelHeight;
F)   int stride = width * ((inputBitmapSource.Format.BitsPerPixel + 7) / 8);

G)   byte[] bits = new byte[height * stride];
H)   inputBitmapSource.CopyPixels(bits, stride, 0);
I)   inputBitmapSource = null;

J)   writeBitmap.Dispatcher.Invoke(DispatcherPriority.Background,
K)   new ThreadStart(delegate
L)   {
M)      //UI Thread
N)      Int32Rect outRect = new Int32Rect(0, 
	(int)(writeBitmap.Height - height) / 2, width, height);
O)      writeBitmap.WritePixels(outRect, bits, stride, 0);
P)    }));
Q) } 

Issues

  1. The component is still very resource hogging. This has been fixed. I just noticed I have to clear the created object myself using DeleteObject if I called Bitmap.GHbitmap, as shown below:
    IntPtr hBitmap = source.GetHbitmap();
    return Imaging.CreateBitmapSourceFromHBitmap
         (hBitmap, IntPtr.Zero, Int32Rect.Empty,
          BitmapSizeOptions.FromEmptyOptions());
    DeleteObject(hBitmap);

References

History

  • 26-12-08 Initial version
  • 28-12-08 Version 1, load thumbnail in thread
  • 28-12-08 Version 2, component updated, demo updated
  • 28-12-08 Article updated
  • 28-12-08 Version 3, border added for thumbnail, and extra large icon
  • 29-12-08 Version 4, folder support, memory usage reduced
  • 30-12-08 Version 5, fixed memory leak, thread EXE icon loading 
  • 31-01-09 Version 6, fixed crash in XP (because XP does not have jumbo icon)

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author


You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
Will Michels18-Jan-13 12:25
memberWill Michels18-Jan-13 12:25 
Question[My vote of 2] Pity it has some dependencies on vbAccelerator and other. Pin
Shimmy Weitzhandler20-Dec-11 14:25
memberShimmy Weitzhandler20-Dec-11 14:25 
QuestionJumbo Icons gets cut and not like in Explorer Pin
budarin6-Oct-11 13:02
memberbudarin6-Oct-11 13:02 
GeneralMy vote of 5 Pin
alexei_c25-Jul-11 12:44
memberalexei_c25-Jul-11 12:44 
GeneralRe: My vote of 5 Pin
Adrian Alexander26-Jul-11 13:45
memberAdrian Alexander26-Jul-11 13:45 
AnswerRe: My vote of 5 Pin
Leung Yat Chun27-Jul-11 1:47
memberLeung Yat Chun27-Jul-11 1:47 
Hello

Thanks for replying, your code works and it's simple, however:

- It support file only.
- The file required valid path (I heavily used PIDL and filepath not parse-able by DirectoryInfo, in my DirectoryInfoEx component).
- It supplies only large icon.

Because of these reasons I have to invoke the WINAPI to obtain the icon.

Regards
Joseph Leung

GeneralTotaly Awesome Pin
highboy20-Nov-10 5:46
memberhighboy20-Nov-10 5:46 
GeneralRe: Totaly Awesome Pin
Leung Yat Chun22-Nov-10 0:31
memberLeung Yat Chun22-Nov-10 0:31 
GeneralRe: Totaly Awesome Pin
highboy24-Nov-10 14:07
memberhighboy24-Nov-10 14:07 
Generalcheck if jumbo image exist Pin
Member 43148085-Mar-10 15:35
memberMember 43148085-Mar-10 15:35 
GeneralRe: check if jumbo image exist Pin
Leung Yat Chun5-Mar-10 20:57
memberLeung Yat Chun5-Mar-10 20:57 
GeneralRe: check if jumbo image exist Pin
Member 43148085-Mar-10 23:39
memberMember 43148085-Mar-10 23:39 
GeneralRe: check if jumbo image exist Pin
Leung Yat Chun6-Mar-10 6:16
memberLeung Yat Chun6-Mar-10 6:16 
GeneralRe: check if jumbo image exist Pin
Member 43148087-Mar-10 7:09
memberMember 43148087-Mar-10 7:09 
GeneralRe: check if jumbo image exist Pin
Laurent Cozic7-Jun-10 23:24
memberLaurent Cozic7-Jun-10 23:24 
GeneralRe: check if jumbo image exist Pin
Leung Yat Chun8-Jun-10 0:32
memberLeung Yat Chun8-Jun-10 0:32 
GeneralGreat work, one bug though with .LNK shortcuts. [modified] Pin
Aybe9-Oct-09 4:15
memberAybe9-Oct-09 4:15 
GeneralRe: Great work, one bug though with .LNK shortcuts. Pin
Leung Yat Chun10-Oct-09 5:27
memberLeung Yat Chun10-Oct-09 5:27 
GeneralRe: Great work, one bug though with .LNK shortcuts. Pin
Aybe11-Oct-09 7:35
memberAybe11-Oct-09 7:35 
GeneralRe: Great work, one bug though with .LNK shortcuts. Pin
Leung Yat Chun12-Oct-09 1:06
memberLeung Yat Chun12-Oct-09 1:06 
GeneralRe: Great work, one bug though with .LNK shortcuts. Pin
Aybe13-Oct-09 3:19
memberAybe13-Oct-09 3:19 
GeneralRe: Great work, one bug though with .LNK shortcuts. Pin
Leung Yat Chun13-Oct-09 5:17
memberLeung Yat Chun13-Oct-09 5:17 
GeneralRe: Great work, one bug though with .LNK shortcuts. Pin
Aybe13-Oct-09 8:33
memberAybe13-Oct-09 8:33 
QuestionGet from OS? Pin
Joel@Novaspect3-Feb-09 4:32
memberJoel@Novaspect3-Feb-09 4:32 
AnswerRe: Get from OS? Pin
Leung Yat Chun4-Feb-09 21:16
memberLeung Yat Chun4-Feb-09 21:16 

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.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150819.1 | Last Updated 30 Jan 2009
Article Copyright 2008 by Leung Yat Chun
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid