September 26, 2008

AIR: Rendering native system icons, Pt.1

I was asked how I got AIR to display native file icons in a component – it’s pretty easy to do, although my method is a little convoluted to explain without posting reams of code, partly because it’s buried in a sequence of Cairngorm events/commands but also because there a couple of important issues to watch for and handle (see bottom of this entry for those). Here’s an overview:

AIR has support for retrieving the native system icons in whatever supported sizes exist. The icons are stored as a property of each File object as BitmapData, in an array, File.icon.bitmaps. Each element in the array is the same icon at different sizes, e.g. 32×32, 16×16 etc.

In order to get at an icon at a given size, you can’t rely on what sizes are available at a given element position, so you need to create a new (empty) BitmapData object at your target dimension, then iterate through File.icon.bitmaps until you hit the matching-sized BitmapData object. Once you have a match, you can put the matching data into your own BitmapData object. Here’s a brief example:

public function get32Icon():BitmapData {
            var myFile:File = new File("C:/foo.txt");
            var bmpData:BitmapData = new BitmapData(32, 32);
            for (var i:uint = 0; i < myFile.icon.bitmaps.length; i++) {
                if (myFile.icon.bitmaps[i].height == bmpData.height) {
                       bmpData = myFile.icon.bitmaps[i];
               return bmpData;

Obviously you need more than the code above to handle situations where the 32×32 icon isn’t available, but that’s a basic way to grab the icon as BitmapData. At this point you could create a new Bitmap object and give it the captured data, but for my application I set the icon data back onto an Object that represents the File object (I actually used an ObjectProxy because I wanted to bind this data to an ItemRenderer later) – again this becomes important later on.

Okay, so now I have my icon data, in an object that also contains other information about the file, like its name etc. To display it in a TileList, or other component, I just use a custom ItemRenderer. I set up an image tag for the icon within the renderer:

<mx:Image width="32" height="32" source="{getIcon(data)}" />

...and then create a method in the renderer to return the icon data to the image component:

private function getIcon(data:Object):Bitmap {
        var bmpData:BitmapData = new BitmapData(32, 32);
        bmpData = data.icon;
        var iconBmp:Bitmap = new Bitmap(bmpData);
        return iconBmp;

Now each time the ItemRenderer has to render an item, it gets the relevant icon, the filename etc. and displays them within the TileList – easy! Here’s the result, showing the app running in XP and OSX:
Files part screen grab

But there are caveats; AIR does not behave consistently on all platforms with icon data. Here are couple of the problems I encountered:

  • Performance. There seem to be some differences in execution time for file system queries in AIR. Originally I had an ArrayCollection of File objects as the DataProvider for the TileList, retrieving icon data for each one in the ItemRenderer as required. On Windows this seemed fine, but on Mac OSX it proved to be very slow, to the point where my app was unusable. I overcame this by using the Flex Profiler to see what was causing the problem, finding that the underlying get icon() execution time was very long on OSX. By grabbing the icon data once, then caching it and other key File properties into an ObjectProxy, I was able to get OSX performance almost on a par with Windows, and this also sped things up elsewhere because I was calling get icon() once, rather than per-item in the renderer. It also improves scrolling performance of the TileList because that component renders items dynamically as they are displayed. In fact you could go one step further than I did and extend UIComponent to improve render performance even more.
  • Missing icons. AIR on Windows won’t retrieve some icons, in particular for .EXE, .TMP and .INI files. These are stored in shell32.dll on XP, but for some reason AIR can’t get to them. I also found one or two similar issues in OSX. AIR on Linux using the most recent AIR beta just returns a null value for File.icon.bitmaps, so rendering native icons is currently impossible. You need to add some way of checking for a missing icon in these cases, and swop it out for an embedded one if you can; I created a temporary workaround where I parse the BitmapData for null pixel values.

The next part of this article will deal with how I got native icons to render for remote files, but I bet you can already guess how that’s done…

- 5 comments by 1 or more people Not publicly viewable

  1. mnieves

    Thanks for the tutorial.
    i have some flash custom as3 class files i like to use in flex that will be a good tutorial how to use flash custom class in flex and what changes.

    26 Sep 2008, 19:33

  2. Ashish


    Thanks for your wonderful example on how to render native icons in AIR. Actually I am trying to make an explorer kind of thing in AIR. could you please share your code for thumbnail view with me? I would be very grateful to you.

    Best Regards,

    29 Sep 2008, 08:33

  3. Ashish


    could you please share your null pixel parsing logic.

    Best Regards

    29 Sep 2008, 10:33

  4. Rui

    And about thumbnail preview of images?

    07 Oct 2008, 11:49

  5. Steven Carpenter

    Hi Rui – can you elaborate on what you mean by thumbnail previews? Are you referring to the icon display or something else?

    07 Oct 2008, 21:46

Add a comment

You are not allowed to comment on this entry as it has restricted commenting permissions.



MXNA link



    Other blogs I like...

    Black Pepper Software

    Eismann-sf Go to 'eismann-sf'

    Ted On Flex Go to 'Ted On Flash'



    Not signed in
    Sign in

    Powered by BlogBuilder
    © MMXV