Windows thumbnails have existed for eons. But in all that time I never really used the windows explorer thumbnail view. Yes, pictures are nice. But invariably I found myself needing the detail view with its listing of file types, sizes and dates.
Well, this week I came across an old stackoverflow thread which mentioned a C# tool for reading and extracting images from the windows thumbnail cache (ie thumbs.db). At least on older XP and Windows 2003 systems. (Vista and later use a slightly different format.) While there are tools galore in this category, the idea of a small DLL that could be called from CF was appealing. So I decided to give it a quick whirl with CF8, under XP.
After compiling the source with Visual C# Express, I changed my explorer settings so I actually had a thumbnails file to test. Next, I created an instance of the ThumbDB class and initialized it by passing in the path my thumbnails database. Once initialized, I used the GetThumbFiles() method to grab an array of all file names within that database.
<cfset util = createObject(".net", "ThumbDBLib.ThumbDB", "c:/test/ThumbDBLib.dll")>
<cfset util.init( "C:/docs/thumbs.db" )>
<cfset fileNames = util.GetThumbFiles()>
<cfdump var="#fileNames#" label="Top 25 Files in Thumbs.db" top="25">
Next, I selected one of the file names and used the GetThumbData() method to retrieve the image bytes. I was hoping to create a CF image object from the bytes and display it in my browser. But every time I called ImageNew(), ColdFusion kept complaining about my argument type.
<!--- this does NOT work --->
<!--- grabbing an arbitrary file from the listing for testing ...--->
<cfset thumbnailName = fileNames[1] />
<cfset bytes = util.GetThumbData( thumbnailName )>
<cfset img = ImageNew(bytes) />
That is when it hit me. A
byte in C# is not the same as
byte in Java. Unlike Java, C# has signed and unsigned types. So where C# has two data types,
sbyte (-128 to 127) and
byte (0 to 255), java has only one,
byte (range -128 to 127). So according to the
data type conversion matrix, the C# byte array was being converted to a
short array.
Thanks to a tip from
BlackWasp.com, I added a new method called
GetJavaThumbData(), which converts the C# byte array into one that is compatible with Java. Using the new method, I was then able to display the thumbnail perfectly.
C# Code:
public sbyte[] GetJavaThumbData(string fileName)
{
byte[] data = GetThumbData(fileName);
if (data != null)
{
sbyte[] jvData = Array.ConvertAll(data, delegate(byte b) { return unchecked((sbyte)b); });
return jvData;
}
return null;
}
ColdFusion Code:
<!--- grabbing an arbitrary file from the listing for testing ...--->
<cfset thumbnailName = fileNames[1] />
<cfset bytes = util.GetJavaThumbData( thumbnailName )>
<cfset img = ImageNew( bytes )>
<cfimage action="writeToBrowser" source="#img#">
It is worth noting the
ThumbDB class also has a method named
GetThumbnailImage(), which returns a C# image object. You can use its properties to display things like height, width, resolution. The class also has several methods for saving the image to a file. Out of curiosity, I tried several of the overloaded save() methods. But I only had success with the simplest form: Image.save(filepath). I am not sure why. Though with CF's own image functions, they are not really needed anyway.
<cfset img = util.GetThumbnailImage( thumbnailName ) />
<cfoutput>
<strong>Thumbnail: #thumbnailName#</strong> <hr />
Height = #img.Get_Height()#
Width = #img.Get_Width()#
PixelFormat = #img.Get_PixelFormat()#
Resolution = #img.Get_HorizontalResolution()# /
#img.Get_VerticalResolution()#
</cfoutput>
Supposedly the
Windows API Code pack can extract thumbnails on later systems like Windows 7. If anyone has used it, or something similar, on Windows 7, let me know. I would be interested in hearing your experiences with it.
Reference: http://cfsearching.blogspot.com/2010/05/experiment-extracting-windows.html