Saturday, December 1, 2012

Recursive Folder Thumbnails

Thumbnails Everywhere

One of the best new features of WinRT is the thumbnail API.  This allows you to very easily grab thumbnails of any type of item in the file system, such as an image, a song, a folder, or any other file type, and Windows will handle returning a proper thumbnail for it.

For images, this is even more useful, as it will take care of positioning and cropping the image correctly, so that an image of any aspect ratio or rotation can be returned in a standard size.  It always crops towards the top center of an image, as that is where the most important part of an image usually is, especially if it is of a person.  This is actually a very important part of how images in Memorylage are displayed.

Here is a great article about how to use the API for any type of thumbnail: Guidelines for thumbnails (Windows Store Apps)

A Minor Annoyance

For folders, the API will look for a file directly within it, and use that to an appropriate thumbnail, such as an image for an image file, or album art for a song.  The problem is that the file must be directly inside the folder, and not within a sub folder.  If you have a folder with many sub-folders (all containing images), but no files directly inside it, then no thumbnail is returned.

For the initial version of Memorylage, I used the GetThumbnailAsync() method as-is, and just displayed a default image if there wasn’t a thumbnail found.  This worked well enough in most cases, but it always bothered me a little seeing defaults in places that they really weren’t needed.  After seeing it mentioned in reviews of the app, and in emails from people using it, I decided to finally fix it up.

The Code

Fixing this was actually fun, because it was one of the few times outside of a classroom that I actually got to use recursion.  I also made it an extension method, so that it can easily be used in place of GetThumbnailAsync().
 
public static class FolderThumbnailExtensions
{
    public static async Task<StorageItemThumbnail> GetThumbnailRecursiveAsync(this StorageFolder inFolder,
        ThumbnailMode mode, uint thumbWidth, ThumbnailOptions options, bool tryThisFolder = true)
    {
        //try to get the thumbnail directly from the folder
        if (tryThisFolder)
        {
            var thumb = await inFolder.GetThumbnailAsync(mode, thumbWidth, options);
            if (thumb != null)
                return thumb;
        }


        //get the sub-folders of the input folder, and return null if there are none
        var folders = await inFolder.GetFoldersAsync();
        if (folders.Count == 0)
            return null;


        //try to find one with a thumbnail
        foreach (var subFolder in folders)
        {
            var thumb = await subFolder.GetThumbnailAsync(mode, thumbWidth, options);
            if (thumb != null)
                return thumb;
        }


        //if we reached this point, none of the sub-folders had a thumbnail, so call this method
        //recursively for each one until you find one
        foreach (var subFolder in folders)
        {
            var thumb = await subFolder.GetThumbnailRecursiveAsync(mode, thumbWidth, options, false);
            if (thumb != null)
                return thumb;
        }


        return null;
    }
}

Conclusion

WinRT shows a lot of promise, and seems to get a lot of things right.  It is still new though, and has quite a few holes compared to Win32 (as does the XAML side compared to WPF).  In the mean time though, many of the things are easy to implement yourself, and plenty of other people are doing so already.
An excellent example that everyone should check out is the WinRT XAML Toolkit.

Let me know if you have found any others.

No comments:

Post a Comment