Important: Version 2 compiled with CxImage 6.00 - Supports all file types.
Introduction
Some months ago, I wrote an article about a C# class that generates thumbnails and a reusable ASP.NET user control that displays thumbnail views. Several people asked me to port my solution to classic ASP. I found some time to do it and here I present the results. The ASP solution is functionally equivalent to that of ASP.NET (in fact, many pieces of code have been translated from C# to VBScript). Only some advanced options are missing (comments showing and editing, beveled thumbnails, thumbnail caching, thumbnail saving) because they are difficult to be implemented in classic ASP. The solution for thumbnail views is reusable and easy to use. You only have to make a virtual include and call a server function inside a form. To generate the thumbnail data in JPEG format, I created an ATL-COM object that is a wrapper of the CxImage
class of Davide Pizzolato. CxImage
is a C++ class to load, save, display, transform BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX, TGA, WMF, WBMP, JBG, and J2K images. The COM wrapper object could be useful for other tasks also. For example, you could create a Web page that lets users apply image processing algorithms on their images.
In this article, I will describe how to use the thumbnail tools and also the important parts of the code.
How to Create a Single Thumbnail and Thumbnail Views
The ASP part of the thumbnail solution consists of the files ThumbGenerate.asp and ListThumbs.inc. After downloading the zip and extracting the files, make the containing ThumbAsp folder a virtual directory and point the browser to the TestListThumbs.asp page. This is a test page, an instance of which is shown in the figure above. Enter in the Virtual Path textbox a path of an IIS virtual-directory containing images, and press the 'Submit' button. You should see the thumbnails of the images residing in that directory. Try the other choices also and see the changes on the thumbnails.
ThumbGenerate.asp is a VBScript code file that can be used in an <img>
tag to produce a thumbnail dynamically in JPEG format. A typical use of the ASP file is shown below. The <a>
link points to an image and the <img>
tag specifies a dynamically generated thumbnail of the same image via its src
attribute value.
<a href='http://www.codeproject.com/santorini/SANTO007.jpg'>
<img src='http://www.codeproject.com/ThumbAsp/ThumbGenerate.asp?
VFilePath=/santorini/SANTO007.jpg&
Width=200&Height=200&Quality=75'
border=0 alt='Name: SANTO007.jpg'/></a>
Parameters to the ASP file are given in the form of a query string. They are the following:
VFilePath
: Virtual path of the original image. The only mandatory parameter. If the file specified does not exist or is not an image, a "no thumbnail" default image is generated from the NoThumb.gif file.
Width
, Height
: Desired thumbnail size. If not given, it is read from appSettings
; if not specified in appSettings
, defaults to 150x150.
Quality
: JPEG quality parameter. Ranges from 1 (lowest quality) to 99 (highest quality). Defaults to 75.
AllowStretch
: Set to 'True
' to allow stretching of thumbnail to fit the above size. If not given, defaults to False
.
ShellThumbnails
: If not specified or set to 'False
', the thumbnail is generated using the CxImage
wrapper object implemented in CxImageATL.dll (ProgID='CxImageATL.CxImage'
). If set to 'True
', the thumbnail is generated using the COM object implemented in ThumbExtract.dll (ProgID='ThumbExtract.FileThumbExtract'
). The latter object exploits the shell interface (IExtractImage
) responsible for generating thumbnails when you click a file or select the Thumbnail view in Explorer. This allows you to create thumbnail views for various file types, e.g., PowerPoint presentations, like in the following figure.
See my article Create Thumbnail Extractor objects for your MFC document types about how to develop a COM object that can extract thumbnails for any file type by implementing the IExtractImage
interface. In the same article, you can find the code for ThumbExtract.dll.
ListThumbs.inc is an ASP file that creates thumbnail views. To use it in an ASP page, you have to include the file as follows:
<!---->
In the position you want the thumbnail view, you call the ListThumbs
function that has the following syntax:
ListThumbs(VPath,Columns,Filter,AllowPaging,PageSize,Width,Height,_
Quality, AllowStretch,ShowFilenames,ShellThumbnails)
The parameters of the ListThumbs
function have the following meaning:
VPath
: Virtual directory that you want to display its contents as thumbnails.
Columns
: Number of columns of the view.
Filter
: Filter to select the files for which you want to display thumbnails (e.g., *.jpg;*.gif).
AllowPaging
, PageSize
: Set AllowPaging=True
to show pages containing PageSize
thumbnails each. For paging to work, you must call the function inside the first form of the ASP document.
Width
, Height
, AllowStretch
, Quality
, ShellThumbnails
: See explanations above.
ShowFilenames
: Set ShowFilenames=True
to show the corresponding filename under each thumbnail.
ListThumbs.inc and ThumbGenerate.asp must be contained in the same virtual directory. Of course, you must register the COM objects also.
Source Code Explanations
As mentioned above, the CxImageATL
object is a wrapper around the CxImage
imaging class. This class has functions to load and save in all popular image formats and also various image processing and manipulation functions. For the thumbnail generation, the Resample
function is used. I added a new function called ImageForASP
that returns the image as a Variant byte array using any supported image format. The returned variant ImageData
can be used to display the image from an ASP page by calling Response.BinaryWrite ImageData
. The ImageType
parameter defaults to 2
(JPEG), and the Quality
parameter defaults to 75
and is used only for the JPEG format.
STDMETHODIMP CCxImage::ImageForASP(long ImageType, long Quality,
VARIANT *ImageData)
{
SAFEARRAY *psaData; BYTE *pData,*pBuffer; long size;
SAFEARRAYBOUND rgsabound[1];
m_image.SetJpegQuality((BYTE)Quality);
CxMemFile memfile; memfile.Open();
bool bOk = m_image.Encode(&memfile, ImageType);
if(!bOk) return E_FAIL; pBuffer=memfile.GetBuffer();
size=memfile.Size();
rgsabound[0].lLbound = 0; rgsabound[0].cElements = size;
psaData = SafeArrayCreate(VT_UI1, 1, rgsabound);
SafeArrayAccessData(psaData, (void **)&pData);
memcpy(pData,pBuffer,size);
SafeArrayUnaccessData(psaData);
free(pBuffer);
ImageData->vt = (VT_ARRAY | VT_UI1);
ImageData->parray = psaData;
return S_OK;
}
ThumbExtract.dll has an equivalent function called ThumbJpgData
that returns thumbnail image data in JPEG format (CxImage
files were used again). Below is the code of the ThumbGenerate.asp file. The only tricky part was how to retain the aspect ratio of the original image. Notice also that the bit depth of the original image must be increased to 24 bits since JPEG does not support indexed images.
<%
Set fso = Server.CreateObject("Scripting.FileSystemObject")
Response.ContentType = "image/jpeg"
Dim VFilePath,FilePath,Width,Height,Quality,bShellThumbnails,
bStretch,bCreate
VFilePath = Request("VFilePath")
If Len(VFilePath)=0 Then VFilePath="NoThumb.gif"
FilePath = Server.MapPath(VFilePath)
If Not fso.FileExists(FilePath) Then
FilePath = Server.MapPath("NoThumb.gif")
End If
If Len(Request("Width"))>0 Then
Width = Int(Request("Width"))
Else Width = 200
End If
If Len(Request("Height"))>0 Then
Height = Int(Request("Height"))
Else Height = 200
End If
If Len(Request("Quality"))>0 Then
Quality = Int(Request("Quality"))
Else Quality = 75
End If
If Len(Request("ShellThumbnails"))>0 Then
bShellThumbnails = (Request("ShellThumbnails")="True")
Else bShellThumbnails = False
End If
If Len(Request("AllowStretch"))>0 Then
bStretch = (Request("AllowStretch")="True")
Else bStretch = False
End If
Dim BinData
If bShellThumbnails Then
Set objThumb = Server.CreateObject("ThumbExtract.FileThumbExtract")
Call objThumb.SetPath(FilePath)
Call objThumb.SetThumbnailSize(Width,Height)
Call objThumb.ExtractThumbnail
BinData = objThumb.ThumbJpgData(Quality)
Else
Set objCxImage = Server.CreateObject("CxImageATL.CxImage")
Call objCxImage.Load(FilePath,GetFileType(FilePath))
Call objCxImage.IncreaseBpp(24)
If Not bStretch Then widthOrig = CDbl(objCxImage.GetWidth())
heightOrig = CDbl(objCxImage.GetHeight())
fx = widthOrig/Width
fy = heightOrig/Height If fx>fy Then f=fx Else f=fy If f<1 Then f=1
widthTh = Int(widthOrig/f)
heightTh = Int(heightOrig/f)
Else
widthTh = Width
heightTh = Height
End If
Call objCxImage.Resample(widthTh,heightTh,2)
BinData = objCxImage.ImageForASP(2,Quality)
End If
Response.BinaryWrite BinData
Function GetFileType(sFile)
dot = InStrRev(sFile, ".")
filetype=2
If dot > 0 Then sExt = LCase(Mid(sFile, dot + 1, 3))
If sExt = "bmp" Then filetype = 0
If sExt = "gif" Then filetype = 1
If sExt = "jpg" Then filetype = 2
If sExt = "png" Then filetype = 3
If sExt = "ico" Then filetype = 4
If sExt = "tif" Then filetype = 5
If sExt = "tga" Then filetype = 6
If sExt = "pcx" Then filetype = 7
GetFileType=filetype
End Function
%>
The source code of the ListThumbs.inc file is listed next. It is essentially a translation from C# to VBScript from my previously presented ASP.NET thumbnail user control. The output that the ASP.NET DataList
control produces can be easily implemented by constructing an HTML table with code. The Columns
parameter determines where the row (<tr>
) tags are placed. However, the editing capabilities of the DataList
control are much more difficult to be implemented with ASP code. For this reason, I did not implement thumbnail comments editing and presentation in this version.
<%
Function ListThumbs(VPath,Columns,Filter,AllowPaging,PageSize,Width,Height,Quality,
AllowStretch,ShowFilenames,ShellThumbnails)
Set fso = CreateObject("Scripting.FileSystemObject")
Set ScriptName = Request.ServerVariables("SCRIPT_NAME")
ScriptPath = Left(ScriptName,InstrRev(ScriptName,"/"))
If Right(VPath,1)<>"/" Then VPath=VPath & "/"
path = Server.MapPath(VPath): If Right(path,1)<>"\" Then path=path & "\"
' analyze filter string
If Len(Filter)=0 Then Filter = "*.gif;*.jpg;*.bmp"
arSuffixes = Split(Filter,";")
For i=0 To UBound(arSuffixes)
pos=Instr(1,arSuffixes(i),".")
If pos>0 Then arSuffixes(i) = Mid(arSuffixes(i),pos) ' e.g. ".gif"
Next
Dim CurPage,TotalPages
' -- write client script and hidden field for current page and path
If AllowPaging Then Call WriteGotoPageScript
If Len(Request.Form("hdnCurPage"))>0 Then
CurPage = CInt(Request.Form("hdnCurPage"))
Else CurPage=1
End If
Response.Write "<input type= CurPage & "' />" & vbCrLf
If Request.Form("hdnPrevPath")<> VPath Then CurPage = 1
Response.Write "<input type='hidden' name='hdnPrevPath' value='" &_
VPath & "' />" & vbCrLf
Dim arrFilesAll(),ubn
If fso.FolderExists(path) Then
Set oFolder = fso.GetFolder(path)
For Each oFile in oFolder.Files
bFileInFilter=False
For i=0 To UBound(arSuffixes)
If IsFileOfType(oFile.Name,arSuffixes(i)) Then bFileInFilter=True
Next
If bFileInFilter Then
ReDim Preserve arrFilesAll(ubn)
arrFilesAll(ubn) = oFile.Name
ubn=ubn+1
End If Next
End If
If AllowPaging Then
TotalPages = CInt(ubn/PageSize)
If ubn Mod PageSize>0 Then TotalPages = TotalPages + 1
if TotalPages=0 Then TotalPages=1
if CurPage>TotalPages Then
CurPage=TotalPages
else
if CurPage<1 Then CurPage=1
end if
StartIndex = (CurPage-1)*PageSize
EndIndex = CurPage*PageSize
If ubn < EndIndex Then EndIndex = ubn
Else
StartIndex = 0: EndIndex = ubn
End If
If fso.FolderExists(path) Then
Response.Write "<TABLE ALIGN='CENTER'>" & vbCrLf
For index=StartIndex To EndIndex-1
FileName = arrFilesAll(index)
Set oFile=fso.GetFile(path & FileName) : FileSize=oFile.Size
nCol = nCol+1
VFilePath = VPath & FileName
sHREF = "<a href='" & VFilePath & "'>" & _
"<img src='" & ScriptPath & "ThumbGenerate.asp?VFilePath=" & _
Server.URLEncode(VFilePath) & "&Width=" &_
Width & "&Height=" & Height &_
"&Quality=" & Quality & _
"&ShellThumbnails=" & ShellThumbnails &_
"&AllowStretch=" & AllowStretch & _
"' border=0 alt='Name: " & FileName &_
" Size: " & CInt(FileSize/1024) &_
" Kb'/> </a>"
If nCol = 1 Then Response.Write "<TR>"
Response.Write "<TD align='Center' " & _
"style='background-color:White;border-width:1px;" &_
"border-style:Solid;font-size:8pt;'>" & vbCrLf
Response.Write sHREF & vbCrLf
If ShowFilenames Then Response.Write "<br/>" & FileName
Response.Write "</TD>" & vbCrLf
If nCol = Columns Then
Response.Write "</TR>" & vbCrLf
nCol = 0
End If
Next
Response.Write NumImagesDisplayed(EndIndex-StartIndex,AllowPaging,ubn,_
CurPage,TotalPages)
If AllowPaging Then
Response.Write CreateNavBar(VPath,CurPage,TotalPages,Columns)
End If
Response.Write "</TABLE>" & vbCrLf
Else
Response.Write "Directory Does Not Exist<P>" & vbCrLf
End If
End Function
Function NumImagesDisplayed(NumDisplayed,AllowPaging,TotalFiles,CurPage,TotalPages)
s = "<tr><td align='Center' colspan='" & Columns &_
"' style='background-color:#FFFFC0;font-size:8pt;'>"
s = s & NumDisplayed
if AllowPaging Then s = s & " of " & TotalFiles
if AllowPaging Then
s = s & " (Page " & CurPage & " of " & TotalPages & ")"
end if
s = s & "</td></tr>"
NumImagesDisplayed = s
End Function
Function CreateNavBar(VPath,CurPage,TotalPages,Columns)
if TotalPages = 1 Then Exit Function
s = "<tr><td align='Center' colspan='" & Columns &_
"' style='font-size:8pt;'>"
if CurPage>1 Then
s = s & "<A href=""javascript:GoToPage('" & VPath &_
"'," & CurPage-1 & _
");""><< Prev</A> "
End If
for i=1 To TotalPages
if i=CurPage Then
s = s & "<b>" & i & "</b>"
else
s = s & "<A href=""javascript:GoToPage('" & VPath &_
"'," & i & ");"">" & _
i & "</A>"
end if
s = s & " "
If i Mod 10=0 Then s = s & "<br/>"
Next
If CurPage<TotalPages Then
s = s & " <A href=""javascript:GoToPage('" &_
VPath & "'," & CurPage+1 & _
");"">Next >></A> "
End If
s = s & "</td></tr>"
CreateNavBar = s
End Function
Function IsFileOfType(afile,infile_type)
IsFileOfType = (UCase(Right(afile,Len(infile_type)))=UCase(infile_type))
End Function
Sub WriteGotoPageScript
Response.Write "<script language=""javascript"">" & vbCrLf & _
"//<!--" & vbCrLf & "function GoToPage(vpath,n) { " & vbCrLf & _
"document.forms(0).hdnCurPage.value=n;" & vbCrLf & _
"document.forms(0).submit(); " & vbCrLf & _
"}" & vbCrLf & "//-->" & vbCrLf & "</" & "script>" & vbCrLf
End Sub
%>
The GoToPage
client JavaScript function that is "injected" in the HTML form implements page navigation. This function is executed at the client side when the user presses any of the page links. It sets the hdnCurPage
hidden field's value equal to the argument n
(that is the page number) and then submits the form. After postback, the page number is retrieved from the hidden field at page load.
Conclusion
I have not yet found on the Web any totally free ASP thumbnail solution, so I hope you'll find this article and the code useful. I recommend you to use the ASP.NET solution if you can, because it is faster and has more options. It seems that the imaging classes of .NET have optimized code. May be if you have a fast PC, you'll not notice the difference, but in my Pentium II, it is obvious.
History
- 8th December, 2002: Initial post.
- 31st October, 2009: Article updated.