When you think ASP, think...
Recent Articles xml
All Articles
ASP.NET Articles
Related Web Technologies
User Tips!
Coding Tips
spgif spgif

Book Reviews
Sample Chapters
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Stump the SQL Guru!
Web Hosts
Author an Article
spgif spgif

ASP ASP.NET ASP FAQs Feedback topnav-right
Print this Page!
Published: Wednesday, August 13, 2003

A Robust Image Gallery for ASP.NET, Part 2

By Robert Van Dyk

  • Read Part 1

  • In Part 1 we examined how to build up an array of JPEG files and subdirectories in a given directory. In this part we'll look at how to generate the required HTML to display thumbnails of the images.

    - continued -

    Emitting the HTML for a JPEG Image

    Before we generate the HTML to be emitted to display the thumbnail for a particular image, we first need to determine the scale factor we will use for the image in order to create its thumbnail. I wasn't planning on showing this, except for the fact that I believe it to be an improvement on the original code from the True Image Resizing article. With the old code, the image was scaled down to the first size-calculated fit that conformed to the min and max parameters set. With the rewritten code, we only accept the best scale down that can be applied to the size of the image. I had to do this, because I wanted to accommodate both images that were long and short and images that were tall and fat equally as well - something I found the old code didn't do well. In the code that follows, currentImage is a System.Drawing.Image object and .Height and .Width are full-scale dimensions.

    imgHeight = currentImage.Height
    imgWidth = currentImage.Width
    Dim scaleFactor as Double
    If imgWidth > maxWidth OR imgHeight > maxHeight then
      If (maxHeight / imgHeight) > (maxWidth / imgWidth) then
        scaleFactor = maxHeight / imgHeight
        scaleFactor = maxWidth / imgWidth
      End If
    End If
    If imgWidth > maxWidth then
      scaleFactor = maxWidth / imgWidth
      imgWidth *= scaleFactor
      imgHeight *= scaleFactor
    End If
    If imgHeight > maxHeight then 
      imgWidth /= scaleFactor
      imgHeight /= scaleFactor	
      scaleFactor = maxHeight / imgHeight
      imgWidth *= scaleFactor
      imgHeight *= scaleFactor
    End If            imgHeight /= scaleFactor	
      scaleFactor = maxHeight / imgHeight
      imgWidth *= scaleFactor
      imgHeight *= scaleFactor
    End If

    Here there are two constants - maxHeight and maxWidth, which specify the maximum height and width, respectively, for a thumbnail. In the code you can toggle the values for these constants, but for the live demo I have them set to 93 and 125 for the height and width.

    The first set of If/Else statements checks to see if the image needs to be scaled at all. If it does, it uses the ratio of deviation between the actual sizes and the maximum acceptable sizes to guess the best scale factor. The second group of If statements checks to see that this is the best scale factor, and if not, selects the better one.

    The next step is to figure out the name of the file, and its size. We do this through a couple of methods that are provided through the .NET Framework.

    Dim filename = Path.GetFileNameWithoutExtension(s)
    If filename.Length > 20
      filename = filename.Substring(0,17) & "..."
    End If
    Dim size As new Integer
    size = fs.Length / 1024

    Here, I declare a String called filename that is set to the filename of the file without any of the path information or extension. Then, I check to see that it is 20 characters or shorter, which effectively constrains the filename to one line of real estate in the 125 pixel wide table element. fs here is an instance of a FileStream object (which is not shown here, but is in the complete code available at the end of this article). The Length property of the FileStream object returns the file's size in bytes. This byte size is then divided by 1,024 to convert that number to kilobytes.

    The final action is to produce the HTML string that will be emitted to the user's browser to display the thumbnail. This string will include a link to open a new image in a JavaScript window whose size is determined by (a) the size of the full- scale image and (b) the size/resolution that your user has his monitor set at.

    An <img> tag is used to actually display the image. Like in the True Image Resizing article, there exists a separate ASP.NET Web page to display the scaled down image. In the previous article this page was called ShowThumbnail.aspx; I decided to rename it to thu.aspx. The only modification is that thu.aspx has a QueryString variable named path that is needed in order to be able to support the recursive subdirectory system. This article does not examine Thu.aspx, it can be used as-is from the download section at the end of this article.

    In addition to displaying the image with an <img> tag, we need to also display some file information, including the image's dimensions and file size. The entire HTML to be emitted for a particular image is done so in the final two lines of AddImage() function:

    DIM PathVar2 = Path.GetFullPath(s.replace(" ","%20"))
    return "<a href=""javascript:NewWindow('" & inSubpageSlash.replace("\","/") & _
           Path.GetFileNameWithoutExtension(s) & _
           "','" & currentImage.Width & "','" & currentImage.Height & "')"">" & _
           "<img src=""thu.aspx?img=" & Path.GetFileName(s.replace(" ","%20")) & _
           "&w=" & imgWidth & "&h=" & imgHeight & "&path=" & _
           PathVar.replace(" ", "%20") & """ border=0></a><br>" & _
           "<div align=center><span style=""font size:'8pt'; font-family:'Verdana';"">" & _
           filename & "<br>" & currentImage.Width & "x" & _
           currentImage.Height & "<br>" & size &  " KB<br></span></div>"

    Since the file that will actually return our thumbnail is thu.aspx?img=filename&w=width&h=height&path=path we need to parse all spaces out of this URL and replace them with the %20 that Web browsers understand. A more robust approach would be to use Server.UrlEncode() here instead.

    Handling Subdirectories

    We want to link to subdirectories so that people can organize their images, otherwise this whole gallery thing isn't very scaleable. To indicate that something is a subdirectory, I create a standard folder looking image that will be displayed for all these items. With a couple of calls to the Path class methods we can determine directory name and how many images and subdirectories it contains.

    The following code exists in the AddDirectoryLink() function, and is called when displaying a subdirectory in the image gallery.

      Dim filesIn = Directory.GetFiles(s, "*.jpg")
      Dim dirsIn = Directory.GetDirectories(s)
      return "<a href=""thumb.aspx?page=1&subpage=" & _
                 inSubpageSlash.replace(" ","%20") &  _
                 Path.GetFileName(s.replace(" ","%20")) & """>" & _
                 "<img width=125 height=93 src=""Folder.jpg"" " & _
                 "border='0'></a>" & _
             "<br><div align=center>" & _
             "<span style=""font size:'8pt'; " & _
             "font-family:'Verdana';"">" & _
             Path.GetFileName(s) & "<br>" & _
             dirsIn.Length & " directories<br>" & filesIn.Length & _
             " images<br></span></div>"
    end try

    The filesIn and dirsIn arrays are used strictly for their .Length property to determine the number of files and subdirectories that the displayed directory contains inside of it. Note that the link that is created has a fairly complicated QueryString variable named subpage, while everything else is pretty easy to follow. In fact, everything else should fall into place because it is done very similarly to the way the files are done.

    The subpage QueryString variable stores the number of subdirectories we've stepped through. In a way, the subpage variable is kind of like an array where each element is separated by a \ mark. InSubpageSlash represents the previous subpage value and Path.GetFileName(s) represents the new directory that is being added to the array. As long as Web browsers do not have a bound on the number of characters they can process in a URL then you can add as many subdirectories as you want to the image gallery (though, I would personally stick to three or four levels, to make it easier on your users.) The trickiest part of the programming comes when I manipulated the subpage variable. Take a look at the code segment below from the HandleDirectoryInput() subroutine:

    Dim inSubpage = Request.QueryString("subpage")
    Dim inSubpageSlash = ""
    If inSubpage <> ""
      inSubpage = inSubpage.replace("%20", " ")
      inSubpageSlash = inSubpage + "\"
      PathVar += inSubpageSlash
      top.text = "<font face='Verdana' size='1'>" & _
                 "<a href=thumb.aspx?page=1>home</a>"
      Dim used = ""
      Dim unused = inSubpage.replace(" ", "_")
      While unused.IndexOf("\") > 0
        used   = inSubpage.subString(0,used.length + _
                                unused.IndexOf("\")).replace(" ", "_")
        unused = inSubpage.subString(used.length+1, _
                               inSubpage.length-used.length-1).replace(" ", "_")
        top.text += " \ <a href=thumb.aspx?page=1&subpage=" & _
                      used.replace("_","%20") & ">" & _
                          used.length-used.lastIndexOf("\")-1) & "</a>"
        used += "\"
      End While
      top.text += " \ " & unused & "</font>"
      top.text = "<font face='Verdana' size='1'>home</font>"
    End If

    Here we are processing the subpage QueryString value and generating the upper part of the table that indicates the current sub-directory. If there is no subpage specified, we know that the user is in the root directory, and therefore can just print out home. Otherwise, we have some processing to do.

    Let me first explain inSubpageSlash. Basically, this is here because inSubpage does not contain a \ character at the end of it, and in order for thu.aspx to work you need to pass it a path that does end with a \. Also, having this variable made things easier to develop when I created the script. It wouldn't be too hard to go work inSubpageSlash out of the code, but sloppy as I am, it is staying put.

    The next two variables I use are used and unused. Basically, initially everything is unused so inSubpage is copied over to that. Then, for every directory that is called out in unused, we need to copy a link to that directory, with a working link including everything up to that point. If the inSubpage variable was pictures\summer\vacation\beach then we need to generate a string that prints the word pictures and links to pictures, followed by summer with a link to pictures\summer, and so on. It continues like that until you get to beach with the link pictures\summer\vacation\beach. Using a fairly high level of string manipulation that relies on the convention that directories are separated by a \ I am able to execute this in a while loop, so that infinite subdirectories are possible.


    Now it is time for you breath a sigh of relief because I am giving away the full version of the code I just explained to you how to write. There are a couple of parts that were left out, though nothing that should be too hard to understand (and if you don't get it, I am willing to help, just drop me an email).

    Also, I recommend that you display thumbs.aspx in an IFRAME like:

      <IFRAME src="thumb.aspx?page=1" width="700" height="330"
                 scrolling="auto" frameborder="0">
            [Your user agent does not support frames or is currently
            configured not to display frames. However, you may visit
            <A href="foo.html">the related document.</A>]
    [View a Live Demo!]

    Also, remember, there is a line near the top of thumbs.aspx that is used to specify the location of the root directory you have your images in that you need to modify. And finally, I would also encourage anyone who does decide to use my code to shoot me an e-mail at vandyr@rpi.edu and tell me how you like (or don't like) it.

    Happy Programming.

  • By By Robert Van Dyk


  • Download the complete code in a ZIP file
  • View a Live Demo!