The PNG Guide is an eBook based on Greg Roelofs' book, originally published by O'Reilly.



Server-Side Workarounds: Content Negotiation

Serving PNG images with the correct MIME type is one thing, but there remains the issue of when to serve PNG images. As discussed earlier, the client-side method involving OBJECT tags really doesn't work very well. The only option that works is content negotiation, and, unfortunately, this only works for those who have control of the web server itself. Content negotiation is also dependent on the web server software being used. But it's conceptually a clean solution, and it has been proven in the field: the World Wide Web Consortium has successfully implemented it at http://www.w3.org since 1996. We'll take a look at how to enable and use content negotiation on the most popular web server in the world: Apache.[18]

[18] The Zeus server is almost identical in configuration. See http://www.zeus.co.uk/products/zeus1/docs/guide/features/content.html for details.

Apache variants files

Apache actually supports two methods of content negotiation. The first involves ``variants'' files and is implemented in Apache's mod_negotiation module. To enable the module, the following line must be added to the httpd.conf configuration file:

AddHandler type-map var

The server must be restarted for this line to take effect. Then, for each image that is to be negotiated, create a .var file corresponding to the filename and refer to that in the HTML file. For example, to serve either tux.gif or tux.png, depending on each browser's capabilities, create a file called tux.var in the same directory and refer to it in the IMG tag in place of the actual image filename:

<IMG SRC="images/tux.var" ALT="[His Penguinness, Tux]">

The contents of tux.var should look something like this:

URI: tux.png
Content-Type: image/png;qs=0.7

URI: tux.gif
Content-Type: image/gif;qs=0.4

Each variant has a corresponding block of information, separated from that of the other variants by blank lines. The actual image filenames are given on the URI lines, and their corresponding MIME types are given on the subsequent Content-Type lines. In addition, a quality of source parameter qs is included for each image type. This is a number between 0.0 and 1.0 that indicates the relative preferences of the author for each image type. In this example, I've indicated that the PNG image (0.7) is preferred over the GIF (0.4). The default value of the qs parameter is 1.0.

A client browser requesting an image from the server also indicates its relative preferences, either explicitly or implicitly, via the HTTP Accept header. The web server then multiplies its quality parameter for each MIME type by the client's quality parameter[19] to get a composite value--this is the resolution phase of the negotiation. The highest composite value determines which image is sent.

[19] Multiplication is specified in the HTTP 1.1 spec; HTTP 1.0 said only to ``combine'' the values.

In practice, things are a bit more complicated for the server, but this is usually hidden from the user. The problem arises when the client browser sends incomplete or even incorrect information. For example, some browsers send Accept: image/* , indicating that they can render any type of image. Others specify a list of image types but also include the catchall type */*. And only rarely does a client include preference values for each type. As a result, the server must assume preference values for the client. By default, all types are given a value of 1.0, but Apache ``fiddles'' the values for wildcard types: image/* or text/* are assigned the value 0.02 instead, and */* is assigned the value 0.01.

The variants file approach allows fine-grained control over every image in a web site, and has the distinct advantage that a site designer can use it at will, if the server administrator has enabled content negotiation. But maintaining parallel sets of images can be enough trouble all by itself; having to maintain a unique variants file for every image is enough to drive most site maintainers to distraction. Fortunately, Apache provides a partial alternative: MultiViews, a directory-wide (and potentially server-wide) method based on file extensions.

Apache MultiViews

Enabling MultiViews in Apache is accomplished by including it on an Options line in the httpd.conf configuration file:

Options +MultiViews

The option may appear inside a <Directory> container, in which case it applies only to the named directory tree rather than the entire server; inside a <VirtualHost> container, in which case it applies only to a given virtual hostname; or, if AllowOverride Options has been specified, within .htaccess files in individual directories. As with variants, the server must be restarted before changes to the main configuration file are noticed.

Once MultiViews is enabled for a given directory--say, /www/htdocs/images--a request for a file foo in that directory will either return foo if it exists or else negotiate between all foo.* files. So to serve either tux.png or tux.gif, for example, simply include both in the directory and refer to them as follows:

<IMG SRC="images/tux" ALT="[His Penguinness, Tux]">

Unfortunately, MultiViews has one great weakness: no version of Apache through 1.3.3 supports multifile quality-of-source settings.[20] In particular, there is no way to add a line or two to one of the top-level configuration files to indicate that all PNGs on the site, or all in a particular directory tree, should have a source quality of, say, 0.7. Individual variants files are still allowed, and if found, their settings will override the Apache defaults. But the requirement to generate one variants file for every image is just as painful with MultiViews as with the standard variants file approach. The only alternative for now is to hack the source, which is precisely what was done at http://www.w3.org/, the home of the W3C. The W3C programmers are working to get their patches cleaned up and incorporated into the stock Apache source tree, but there is no word on when that will occur, and in the meantime, the Apache developers ``have no firm plans to add such functionality.'' As with many such things, multiple user requests for the feature would probably make a difference in the development plans.

[20] Version 1.3.4 was released a few weeks before this book's deadline; the ``New Features in Apache 1.3'' page (http://www.apache.org/docs/new_features_1_3.html) hinted at changes relevant to a global quality-of-source feature, but I did not have time to investigate fully. Specifically, the three server configuration files were merged (srm.conf and access.conf were absorbed into httpd.conf/), and the mod_negotiation module was ``completely overhauled.'' A comment in the mod_negotiation source code, however, indicates that the global setting still has not been implemented.




Last Update: 2010-Nov-26