Work the Shell

Displaying Image Directories in Apache, Part II

Dave Taylor

Issue #157, May 2007

Get the Apache images in thumbnails by putting everything in a for loop.

Last month, we started writing a shell script to turn the boring Apache directory display into a more useful and visually interesting page that helps you figure out what images you have and what they look like.

By utilizing the file command, I showed how you easily can differentiate between files that actually are images and those that aren't, so you don't get into an awkward situation where you're trying something like this:

<img src=mypage.html alt=mypage.html />

If you tell the Web browser to try to display an HTML source file as an image, well, the results aren't going to be what you desire!

Everything in a for Loop

The basic script iterates through every file in the current directory with a for loop, using the common shell construct:

for name in *
do
   commands
done

Let me point out that this won't display files that start with a ., which is good in that it doesn't display . and .., but which is potentially a problem if you were being tricky and had filenames like .secret-pict.png. But, then again, if you're trying to hide files by making them dot files, it's not unreasonable that this script glosses over them too.

As I've shown earlier, if you do have an image file, the best way to display it in HTML is to use something akin to:

<img src="filename" alt="filename" />

A better solution is maybe to label the image in the alt tag, but let's just jump into the loop and add this code. Recall that I'm using the file command to figure out what's an image and what isn't, so now our core loop looks like this:

for name in *
do
  if [ ! -z "$(file $name | grep 'image data')" ]
  then
    echo "<img src=$name><br />$name<br /><br />"
  else
    echo "<a href=$name>$name</a><br /><br />"
  fi
done

This works pretty well, displaying the images (and their names) for those files that are recognized as images, and just displaying a hypertext reference to the other files in the directory without erroneously indicating they're images.

Thumbnails Please

The problem with this approach is demonstrated quickly if, like me, you have lots of variable-size images; the resultant page is huge! What I really want displayed are small thumbnails or previews of my images, not the big images themselves.

Fortunately, Web browsers are pretty darn good at scaling images if you ask them to do the work. For example, if you have a 300x300 image but specify a height and width of 50, the image is scaled and displayed as 50x50 in the browser automagically. What you might not realize is that browsers also can scale an image if you simply specify either a different height or width value. In other words, this works fine:

<img src=100x100.png height=50 />

That's good news, because although you can figure out the size of an image on the fly in your shell script, it's fairly complicated. So, if we simply can specify that one parameter always should be a given height, you quickly can get quasi-thumbnails, albeit sometimes oddly sized ones.

The problem, by the way, is if we say that we always want images to be 50-pixels high and scale appropriately, an image that's 480 wide by 50 wide becomes, well, a 480-pixel-wide thumbnail. Ideally, our thumbnails would fix into a 50x50 box instead, but let's start with a basic solution:

for name in *
do
  if [ ! -z "$(file $name | grep 'image data')" ]
  then
    echo "<img src=$name alt=$name height=50 />"
    echo "<br />$name<br /><br />"
  else
    echo "<a href=$name>$name</a><br /><br />"
  fi
done

I also added an alt attribute to the img, though it doesn't really make any difference in the display. As you can see in Figure 1, the display overall is pretty nice. But, I have one image, logo-small.png, that turns out to be 850x40, so forcing a height of 50 pixels actually increases its width, by scaling up, not down!

Figure 1. Example Thumbnail Display

Figuring Out Image Size

It would be quite useful to be able to ascertain the size of an image and scale it appropriately. In some versions of Linux, you can get the image size information from the file command itself:

$ file xml.gif walt-disney-world-logo.jpg zeralights-logo.png
xml.gif:  GIF image data, version 89a, 36 x 14,
walt-disney-world-logo.jpg: JPEG image data,
JFIF standard 1.01, resolution (DPI), "AppleMark", 72 x 72
zeralights-logo.png: PNG image data, 225 x 93,
8-bit/color RGB, non-interlaced

The problem here is that the file command doesn't know how to ascertain the size of JPEG files, so the 72x72 reported for the image walt-disney-world-logo.jpg is actually the resolution of the image, not its size—a terrible limitation, but one we can live with, albeit reluctantly. Anyway, you should be using PNG format, not JPEG, right?

Based on that output, here's a shell function that returns height and width for GIF and PNG images and a null value for JPEG and any non-image files:

figuresize()
{
   image=$1

   fileout="$(file -b "$1")"

   if [ ! -z "$(echo $fileout|grep "GIF image")" ]
   then
     # GIF image, width x height are params 6-8
     width=$(echo $fileout | cut -f6 -d\  )
     height=$(echo $fileout | cut -f8 -d\  )
   elif [ ! -z "$(echo $fileout|grep "PNG imag")" ]
   then
     # PNG image, width x height are params 4-6
     width=$(echo $fileout | cut -f4 -d\  )
     height=$(echo $fileout | cut -f6 -d\  )
   else
     height=""; width=""
   fi
}

This is now integrated easily into our original loop, so we also can display the size of the image in our output:

for name in *
do
  if [ ! -z "$(file -b $name|grep 'image data')" ]
  then
    figuresize $name
    if [ ! -z "$height" ] ; then
      echo "<img src=$name alt=$name height=50 />"
      echo "<br />$name ($height x $width)<br />"
    else
      echo "<img src=$name alt=$name height=50 />"
      echo "<br />$name<br />"
    fi
  else
    echo "<a href=$name>$name</a><br /><br />"
  fi
done

I've run out of space to show how you can use that information to change how you scale your thumbnails, so that'll have to cascade into next month, but I encourage you to experiment with this code a bit and see what kind of results you get. Also, as a tip, if you want to get the size of all image types reliably, there's no better toolkit to add to your Linux box than ImageMagick, which you can find at www.imagemagick.org.

Dave Taylor is a 26-year veteran of UNIX, creator of The Elm Mail System, and most recently author of both the best-selling Wicked Cool Shell Scripts and Teach Yourself Unix in 24 Hours, among his 16 technical books. His main Web site is at www.intuitive.com, and he also offers up tech support at AskDaveTaylor.com.