Click here to Skip to main content
15,867,141 members
Articles / Desktop Programming / ATL

An ASP Thumbnail Solution

Rate me:
Please Sign up or sign in to vote.
4.88/5 (41 votes)
19 Nov 2009CPOL6 min read 437.8K   8.1K   100   108
ASP pages and free COM objects for generation of thumbnails and thumbnail views.

Sample Image - ThumbTools2-1.jpg

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.

HTML
<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.

PPT-file thumbnails using the shell-thumbnail extract object

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:

HTML
<!-- #include virtual ="/ThumbAsp/ListThumbs.inc" -->

In the position you want the thumbnail view, you call the ListThumbs function that has the following syntax:

VBScript
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.

C++
// method to display image in ASP pages
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; // NO-IMAGE
    pBuffer=memfile.GetBuffer();
    size=memfile.Size();
 
    // create safe array and copy image data
    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);
    // put data in variant
    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.

VBScript
<%
Set fso = Server.CreateObject("Scripting.FileSystemObject")
 
Response.ContentType = "image/jpeg"
' ---- parameter parsing ----'
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
 ' Create COM Shell Thumbnail object
  Set objThumb = Server.CreateObject("ThumbExtract.FileThumbExtract")
  Call objThumb.SetPath(FilePath)
  Call objThumb.SetThumbnailSize(Width,Height)
  Call objThumb.ExtractThumbnail
  BinData = objThumb.ThumbJpgData(Quality)
Else
 ' Create COM CxImage wrapper object
  Set objCxImage = Server.CreateObject("CxImageATL.CxImage")
  Call objCxImage.Load(FilePath,GetFileType(FilePath))
  Call objCxImage.IncreaseBpp(24)
  ' determine thumbnail size and resample original image data
  If Not bStretch Then ' retain aspect ratio
     widthOrig = CDbl(objCxImage.GetWidth())
     heightOrig = CDbl(objCxImage.GetHeight())
     fx = widthOrig/Width
     fy = heightOrig/Height 'subsample factors
     ' must fit in thumbnail size
     If fx>fy Then f=fx Else f=fy  ' Max(fx,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
 
' output in Response '
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.

VBScript
<%
 
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='hidden' name='hdnCurPage' value='" &_
                 CurPage & "' />" & vbCrLf
                ' restart page numbering if different page
  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 ' if in filter
    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
    ' make sure current page is in the [1,totalPages] range
   if CurPage>TotalPages  Then
     CurPage=TotalPages
   else
     if CurPage<1 Then CurPage=1
   end if
   ' range of files to read
   StartIndex = (CurPage-1)*PageSize
   EndIndex = CurPage*PageSize
   If ubn < EndIndex Then EndIndex = ubn
  Else
   StartIndex = 0: EndIndex = ubn
  End If
  ' write thumbnail hrefs
  If fso.FolderExists(path) Then
    Response.Write "<TABLE ALIGN='CENTER'>" & vbCrLf
    For index=StartIndex To EndIndex-1
      FileName = arrFilesAll(index)
      ' Response.write path & FileName
      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 &_
                  "&#10;&#13;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
 ' s = s & " images"
 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
  'GoToPage client script updates hidden field with target page
  'and then causes a postback
  s =  s & "<A href=""javascript:GoToPage('" & VPath &_
         "'," & CurPage-1 & _
   ");"">&lt;&lt; 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 &gt;&gt;</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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer Forthnet
Greece Greece
Software developer and Microsoft Trainer, Athens, Greece (MCT, MCSD.net, MCSE 2003, MCDBA 2000,MCTS, MCITP, MCIPD).

Comments and Discussions

 
GeneralRe: Javascript Error Pin
shemesh16-Dec-03 11:45
shemesh16-Dec-03 11:45 
GeneralRe: Javascript Error Pin
Nancyr29-Apr-05 6:42
Nancyr29-Apr-05 6:42 
Generaltestcximage does work on win98,me Pin
lkuzar10-Mar-03 11:57
susslkuzar10-Mar-03 11:57 
GeneralRe: testcximage does work on win98,me Pin
zwangarry27-Oct-03 6:28
zwangarry27-Oct-03 6:28 
GeneralTIFF Images Pin
zzzyzx24-Feb-03 12:12
zzzyzx24-Feb-03 12:12 
Generalasp resize Pin
mml77010-Feb-03 10:24
mml77010-Feb-03 10:24 
GeneralRe: asp resize Pin
mml77010-Feb-03 10:26
mml77010-Feb-03 10:26 
GeneralCool Pin
Anonymous10-Dec-02 9:52
Anonymous10-Dec-02 9:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.