Server-Side Image Manager

by Steve Waldman <swaldman@mchange.com>

© 2003 Machinery For Change, Inc.

This software is made available for use, modification, and redistribution, under the terms of the GNU Public License (GPL).


Contents

  1. Contents
  2. Basics
  3. Prerequisites
  4. Using SSIM as a Servlet in a Java Web Application
  5. Using SSIM to manage images for a non-Java website
  6. SSIM as a Stand-Alone Service
  7. Using SSIM to manage both web-app images and certain external images
  8. Appendix A: Initialization Parameters
  9. Appendix B: Request Parameters
  10. Appendix C: Sample web.xml

Basics

Server-Side Image Manager is a library designed to simplify the management of images on websites. In particular, webites often require that the same basic image be made available in multiple sizes. Common examples include icons or logos, which may be dispersed throught a website in many sizes, or photographs which are presented in thumbnail form, and then are made available at multiple resolutions.

There are many approaches to dealing with the problem of multiple scaled images, but none of them are great. Lazy webmasters just supply a large image and use HTML width and height attributes to force clients to scale the images, but this is inefficient: to display even an icon or thumbnail, the client has to download the oversized image and rescale it, wasting bandwith and client CPU. More diligent webmasters prescale the image by hand to each desired size. But, this approach is a pain in the ass, a maintenance problem — every time an image changes, or a new size is desired, the webmaster must remember to reproduce all required scaled instances.

Server-Side Image Manager allows webmasters to get the performance and efficiency advantages of prescaling without the maintenance problems. SSIM transforms images into dynamic rather than static resources. For example, an HTML page might reference an image tags that look like any of the following:

<img src="cool_pic.jpg?width=50">
references cool_pic.jpg, scaled to a width of 50 pixes and its natural, aspect-ratio-preserving height.
<img src="cool_pic.jpg?height=50">
references cool_pic.jpg, scaled to a height of 50 pixes and its natural, aspect-ratio-preserving width.
<img src="cool_pic.jpg?width=200&height=300">
references cool_pic.jpg, scaled to a width of 200 pixels and a height of 300 pixels, even if this results in the image being distorted.
<img src="cool_pic.jpg?width=200&height=300&preserveAspectRatio=true">
references cool_pic.jpg, scaled to the maximum size possible that will fit within a bounding box of width 200 and height 300, but that preserves the image's natural aspect ratio.
<img src="imageservlet?imageUrl=http://foo.booboo.com/faraway_pic.jpg?width=200">
references faraway_pic.jpg on some other server, scaled to a width of 200 pixels

Server-side Image Manager caches the images it generates and serves, so, after the first request for a scaled version, users see performance similar to static images. Great care has been taken in the development of the library to ensure maximum concurrent access to images, while making sure that clients never see incomplete or broken images while images are being scaled and cached.

Server-side Image Manage can be used as a Servlet in java-based web applications, or, in combination with a standalone servlet environment, as a service that non-Java based websites can use to manage their images.

Prerequisites

SSIM requires a that a Java Virtual Machine, version 1.4 or higher, and a Java Servlet environment, version 2.3 or higher, be the server that will manage your images. Users who wish to run SSIM in combination with a non-Java webserver can do so by setting up the free Tomcat server as a standalone service. If you wish to use SSIM as a service for an external, non-Java web-application, it will be helpful to install Apache Ant, which will "automagically" do the Java-specific stuff required to use SSIM.

Using SSIM as a Servlet in a Java Web Application

If you plan to use Server-Side Image Manager as a servlet, you should already be familiar with the how to deploy Java Servlets and web applications. Nothing more will be required of you than adding SSIM's jar file to your web-application, and configuring the servlet in your web.xml file. See the sample web.xml in Appendix C below.

The classname of the SSIM's servlet is com.mchange.v2.ssim.SsimServlet. You'll need to be sure that all requests to images that should be handled by the servlet get mapped to the servlet, usually by providing suffix url-mappings such as *.gif, *.jpg, etc. See the sample.

The servlet accepts a bunch of initialization parameters, which are described in detail in Appendix A. While all initialization parameters are optional, you'll probably want to set at least cacheDir, since it defaults to using the web applications temporary directory, which may not be preserved between web application restarts.

Using SSIM to manage images for a non-Java website

You can plug SSIM into apache or other webservers and let it manage your images for you. You'll have to figure out how to run Java servlets and web applications in combination with your webserver. One common configuration is to use the Apache webserver, Apache Jakarta Tomcat, and mod_jk or mod_jk2. You'll also need to install Apache Ant.

The SSIM distribution contains a directory called build-service. Enter this directory, edit the file build.properties to set up your initialization parameters, and then type ant. This will build your service web application, which you will find as a war file (ending in .war) underneath the directory called dist that will appear after you've run ant. Configure your webserver to deploy this Java web application, and that's it! (All of this will be easy if you're used to deploying Java web-apps in your environment. It might be a pain and a lot of configuring if you're not...)

The crucial thing is to get the initialization parameters right in build.properties. Let's say you have an existing website, whose document root is /usr/local/web, and you want to make its images scalable. You'd edit build.properties to look something like this:

# # The name of the war file that should be generated # WITHOUT THE .war SUFFIX (e.g. use "images" to generate # "images.war") # # REQUIRED # web.app.name=scaledimages # # Servlet Initialization Parameters # all are optional, but cacheDir and cacheSize are strongly recommended # (Please see Server-Side Image Manager documentation!) # # Uncomment and supply the ones you want # baseUrl.init.param=file:///usr/local/web/ cacheDir.init.param=/var/tmp #cacheSize.init.param= #cullDelay.init.param= #maxWidth.init.param= #maxHeight.init.param= #allowDomains.init.param=
You'd run ant, then deploy the images.war file you'd find under build-service/dist, under the alias (or in Java-speak contextPath) /scaledimages. You'd go through your web application and for any images you'd like scaled, change the image tags like <img src="/icons/logo.gif" width="200"> to <img src="/scaledimages/icons/logo.gif?width=200">.(You'd need to be careful of image source urls specified relative to the HTML page, and change them to absolute URLs based on the webserver's document root (URLs beginning with "/") if you want SSIM to scale these images.

SSIM as a Stand-Alone Service

You can use SSIM as a "standalone" image server, put your images in its care, and let your non-Java website refer to the images via absolute URLs. Just download Jakarta Tomcat, configure a web-application as described above, add the war file to Tomcat's web-app directory and Voila! you have a dedicated, scaling HTTP server for your images.

Using SSIM to manage both web-app images and certain external images

[Advanced] It is frequently useful to have images both internal to a Java web application and external to the application's war file be managed by SSIM. For example, if you want to write a photoalbum application, you might wish to let the images be stored in some easily modifiable external directory, but also have images internal to the web-application itself. You can do this by defining a web-application-scoped variable (i.e. a ServletContext attribute) under the name com_mchange_v2_ssim_SsimServlet__patternReplacementMap, which must be of type com.mchange.v2.util.PatternReplacementMap (see javadocs). If you do this, SsimServlet will check each requests path (URI) against a list of regular expression. If the path matches, SSIM substitute the replacement path you specify for the original. The replacement paths may depend upon the originally requested path, by virtue of the common regular expression convention that allows regexes to contain parenthesized subgroupings, and regex replacement expressions to refer to those groupings as $1 for the first subgrouping, $2 for the second, and $0 for the whole matching expression. The replacements should be absolute URLs. They may be file: URLs.

Any path that resolves to a URL via the PatternReplacementMap will be retrieved from this URL. These paths are considered trusted -- no further security checks will be performed -- and they take precedence over any baseResourcePath or baseUrl you may have set.

Appendix A: Initialization Parameters

allowDomains
A comma separated list of domains from which SSIM should be willing to fetch, scale, and reserve images, when requests contain an explicit imageUrl parameter. If not specified, only imageUrls from the same subdomain as the request, or to localhost if you are running locally, will be allowed. If set to the special value all, the Servlet will be allowed to retrieve and scale images from any URL. If set to the special value none specifying imageUrl as a request parameter is forbidden will result in an error.
baseResourcePath
A path, relative to the root of the web-application in which an SSIMServlet is running, that should be prepended to pathInfo in finding source images (when no explicit imageUrl is specified). Effectively defaults to / when not specified. Only one of baseResourcePath and baseUrl can be explicitly specified.
baseUrl
A url that should be prepended to pathInfo in finding source images (when no explicit imageUrl is specified). This URL can be a file: URL, allowing you to keep your source images separate from your web application. Effectively defaults to the return value of request.getResource("/") when not specified. Only one of baseResourcePath and baseUrl can be explicitly specified.
cacheDir
The absolute path to a directory where SSIM can put its image cache. It is strongly recommended that you supply this parameter, as it defaults to the web application's temporary directory, which may not be retained between web-app restarts. Note that this directory must exist and be writable by the Java servlet container (e.g. tomcat).
cacheSize
The maximum size (in megabytes) that SSIM should permit for its scaled image cache. SSIM will cull least-recently-used images when the cache size exceeds this value. Defaults to 50. If less than or equal to 0, the cache will never be culled cache size will unlimited.
cullDelay
The number of seconds SSIM should wait between checks to see if the cache has exceeded the cache size and must be culled. Defaults to 300 (five minutes). If less than or equal to 0, the cache will never be culled cache size will unlimited.
maxConcurrency
The maximum number of images SSIM will simultaneously attempt to scale. Defaults to 3. If this value is too high, SSIM may simultaneously attempt to scale many large images, and provoke OutOfMemoryErrors.
maxWidth
The maximum width (in pixels) that clients can request images scale to. Defaults to 2000. If less than or equal to zero, SSIM will scale images to unlimited widths.
maxHeight
The maximum height (in pixels) that clients can request images scale to. Defaults to 2000. If less than or equal to zero, SSIM will scale images to unlimited heights.

Appendix B: Request Parameters

width
The width to which an image should be scaled. If supplied without height the image will scale to this width and while maintaining its natural aspect ratio. If height is supplied as well, the image may be distorted, unless preserveAspectRatio is also supplied, in which case the image will scale as large as possible up to a maximum of this width, but no wider than the natural aspect ratio would permit given an accompanying height constraint.
height
The height to which an image should be scaled. If supplied without width the image will scale to this height and while maintaining its natural aspect ratio. If width is supplied as well, the image may be distorted, unless preserveAspectRatio is also supplied as true, in which case the image will scale as large as possible up to a maximum of this height, but no wider than the natural aspect ratio would permit given an accompanying width constraint.
imageUrl
The full URL (often URL encoded) of the original image to be scaled. Rather than finding the image to scale based on the pathInfo of the request, SSIM can accept an explicit image URL, which needn't be on the same server as the SSIMServlet. The allowDomains initialization parameters determines whether or not SSIM will be permitted to scale and serve a foreign image.
mimeType
[Experimental] SSIM can not only scale images, but can also interconvert between image types. For example, if you have an image in PNG format, but you wish to make it available to old or crippled browsers that don't support this format, you might use a url like myImage.png?mimeType=image/jpeg (or in URL-encoded form myImage.png?mimeType=image%2fjpeg) which would cause the image to be converted on the fly to JPEG format, and for the converted image to be cached for future use. Mime-type interconversions and scaling can be combined freely.
preserveAspectRatio
If this parameter set to true, than any width and height request parameters are treated as defining a bounding-box, within which the image will be scaled to the maximum possible size that retains the natural aspect ratio of the image.

Appendix C: Sample web.xml

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>ssim-example</display-name> <servlet> <servlet-name>imageScaleServlet</servlet-name> <servlet-class>com.mchange.v2.ssim.SsimServlet</servlet-class> <init-param> <param-name>cacheDir</param-name> <param-value>/web/tmp/photo.mchange.com</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.JPG</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.jpeg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.JPEG</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.gif</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.GIF</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.png</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>imageScaleServlet</servlet-name> <url-pattern>*.PNG</url-pattern> </servlet-mapping> </web-app>

Back to Contents