If you’ve ever visited an image library on the Internet, you’ve probably enjoyed (even taken for granted) the way a collection of small thumbnail images acts as links for full-sized counterparts. Many artists, when presenting a portfolio online, adopt this effective approach to displaying their work. With the rise of digital cameras and scanners, more and more people are finding themselves pulling directories full of images onto the Web in a format that makes for easy browsing. In the next section, we build a Python script that takes a full directory of images and thumbnail images and creates a master HTML page with the thumbnails acting as links to the full-size image. The saxthumbs.py program expects you to have a pre-existing directory of images and thumbnails, and operates on the output of the index.py script we created earlier.
In order for the saxthumbs.py
SAX handler to correctly process a thumbnail directory, the images need
to follow a naming convention (easily changeable by editing the code).
Currently, the saxthumbs.py handler
expects to find file
elements within
the XML document that have a corresponding <imagename>.jpg file that is the entire
image, and a t-<imagename>.jpg file that is a
thumbnail-size image.
When using index.py to create a list of your image files, point it to a directory that has image files named accordingly:
$> ls -l *newimage* -rw-rw-r-- 1 shm00 shm00 98197 Jan 18 11:08 newimage.jpg -rw-rw-r-- 1 shm00 shm00 5272 Jan 18 11:42 t-newimage.jpg
In this manner, every file that ends in .jpg and has a corresponding t-<imagename>.jpg file (note the size differences) is assimilated into the thumbnail index.
There is an easy way to set up your image files on Unix
systems, using the convert
command.
This command is part of the ImageMagick package, and is installed by
default by most modern Linux distributions. For other Unix systems,
the package is available at http://www.imagemagick.org/.
$> convert image.jpg -geometry 192x128 t-image.jpg
This will take image.jpg, no matter how large it is, and make a 192x128 size thumbnail in JPEG format. Of course, if the image is a Windows bitmap image (with the .bmp extension), you can do a two-step operation to get JPEG files:
$> convert image.bmp image.jpg $> convert image.jpg -geometry 192x128 t-image.jpg
Now that you understand how convert
works, you can use a simple shell
loop to produce small thumbnail images for every .jpg in your image directory:
$> for each in *jpg > do > convert $each -geometry 192x128 t-$each > echo $each > done
You should end up with the following:
-rwxrwxr-x 1 shm00 shm00 97003 Jan 16 22:40 mvc-001s.jpg -rwxrwxr-x 1 shm00 shm00 93373 Jan 16 22:40 mvc-002s.jpg -rwxrwxr-x 1 shm00 shm00 86619 Jan 16 22:40 mvc-003s.jpg -rwxrwxr-x 1 shm00 shm00 94894 Jan 16 22:40 mvc-004s.jpg -rwxrwxr-x 1 shm00 shm00 76210 Jan 16 22:40 mvc-005s.jpg -rwxrwxr-x 1 shm00 shm00 73704 Jan 16 22:40 mvc-006s.jpg -rwxrwxr-x 1 shm00 shm00 80292 Jan 16 22:40 mvc-007s.jpg -rw-rw-r-- 1 shm00 shm00 4434 Jan 21 11:46 t-mvc-001s.jpg -rw-rw-r-- 1 shm00 shm00 4181 Jan 21 11:46 t-mvc-002s.jpg -rw-rw-r-- 1 shm00 shm00 3604 Jan 21 11:46 t-mvc-003s.jpg -rw-rw-r-- 1 shm00 shm00 4634 Jan 21 11:46 t-mvc-004s.jpg -rw-rw-r-- 1 shm00 shm00 3339 Jan 21 11:46 t-mvc-005s.jpg -rw-rw-r-- 1 shm00 shm00 2777 Jan 21 11:46 t-mvc-006s.jpg -rw-rw-r-- 1 shm00 shm00 2996 Jan 21 11:46 t-mvc-007s.jpg
This listing represents the convert
program applied against mvc-00*.jpg files taken with a digital
camera. The saxthumbs.py script
produces markup to display both the thumbnails and each individual
image.
If you run index.py against this directory, you create an XML file that we are able to use a little later in the chapter when we go over the saxthumbs.py process:
$> ./index.py /home/shm00/images/ img.xml
The new file, img.xml, contains file elements that detail your image files in a format appropriate for the script to manipulate.
If you don’t have access to Unix (or a scriptable image processor for your operating system), you can create your own image directory on Windows. Just be sure to resize originals and prefix the thumbnails with t-, and make sure that all of the images to be displayed on the Web are in JPEG format (ending with .jpg). For example, if you open the My Pictures directory in Photoshop, you can take each image, resize it to 192x128, and save it as a t- version of its original self.
To come back around to our example, once you prepare the directory, you can point index.py at it and generate an XML index file for the images.
The SAXThumbs
handler
creates an anchor for each thumbnail in the HTML output file, and
creates a standalone HTML document to display the full size image.
Then, SAXThumbs
leaves you with an
HTML page showing all of your thumbnails, as well as an HTML page for
each full size image.
The SAXThumbs
handler is
implemented as a class inheriting from ContentHandler
. The name of the output file,
which should contain a preview of all of the thumbnails, is supplied
as a command-line parameter and passed to the constructor:
def __init__(self, thumbsFilename): self.filename = thumbsFilename def startDocument(self): self.fd = open(self.filename, "w") self.fd.write("<html><body> ") def endDocument(self): self.fd.write("</body></html> ") self.fd.close( )
When the end of the XML document is reached, it’s assumed that there are no more image files to process, and the thumbnails document is closed.
The rest of the work is done in the startElement
method. First, the image name
is copied without its path information:
def startElement(self, name, attrs): if name == "file": filename = attrs.get("name", "") # pull out just the filename dir, localname = os.path.split(filename) localname, ext = os.path.splitext(localname)
Then, the file is examined to determine whether it’s a thumbnail or a full image. Thumbnails have HTML anchors around them, which are then added to the thumbnails output file:
if localname.startswith("t-") and ext == ".jpg": # create anchor tag in thumbs.html fullImgLink = localname[2:] + ".html" self.fd.write('<br><a href="%s"><img src="%s%s"></a> ' % (fullImgLink, localname, ext))
If the image is not a thumbnail, but a full image, then a separate HTML file is created that displays the image:
fullImageFile = os.path.join(dir, localname) + ".html" print "Will create:", fullImageFile fullImageHTML = ('<html><body><img src="%s%s"></body></html> ' % (localname, ext)) lfd = open(fullImageFile, "w") lfd.write(fullImageHTML) lfd.close( )
The full-image HTML file is created in the same directory that holds the image. The thumbnails file is created in the same directory from which you’re running thumbmaker.py. Example 3-6 shows saxthumbs.py.
from xml.sax import ContentHandler class SAXThumbs(ContentHandler): """ This is the SAX handler that generates a full- image display (an .html page) for each image file contained in the XML file. It also adds an anchor on the thumbs page showing the thumbnail, and linking to the big image page that was created first. """ def __init__(self, thumbsFilename): self.filename = thumbsFilename def startDocument(self): self.fd = open(self.filename, "w") self.fd.write("<html><body> ") def endDocument(self): self.fd.write("</body></html> ") self.fd.close( ) def startElement(self, name, attrs): if name == "file": filename = attrs.get("name", "") # slice out just the filename dir, localname = os.path.split(filename) localname, ext = os.path.splitext(localname) if localname.startswith("t-") and ext == ".jpg": # create anchor tag in thumbs.html fullImgLink = localname[2:] + ".html" self.fd.write('<br><a href="%s"><img src="%s%s"></a> ' % (fullImgLink, localname, ext)) fullImageFile = os.path.join(dir, localname) + ".html" print "Will create:", fullImageFile fullImageHTML = ('<html><body><img src="%s%s"></body><html> ' % (localname, ext)) lfd = open(fullImageFile, "w") lfd.write(fullImageHTML) lfd.close( )
The thumbmaker.py
file is a script that loads the XML from standard input, and registers
the SAXThumbs
class as the chosen
handler to use with the SAX parser. Example 3-7 shows thumbmaker.py in its entirety.
#!/usr/bin/env python # thumbmaker.py import sys from xml.sax import make_parser from saxthumbs import SAXThumbs # Main ch = SAXThumbs(sys.argv[1]) parser = make_parser( ) parser.setContentHandler(ch) parser.parse(sys.stdin)
It is interesting to note the similarity to the first script that we wrote in Example 3-2.
To run thumbmaker.py, you first need to make sure you have created the right type of directory containing image files and that you’ve run index.py across the directory to generate an XML file containing the list of files. Once you have these items, you can pick a name for the index file (such as mythumbs.html) and pass it to the script:
$> python thumbmaker.py mythumbs.html < img.xml
In this case, mythumbs.html is the output file, and the XML source is received from the file img.xml.