[Image] EchoPoint
Helping you build truly dynamic and stateful web applications!
nothing

Using Images in Echo

By Brad Baker
Wednesday, February 11, 2004

Images are a corner stone of web applications.  Virtually all web applications use images to present information. 

So it makes sense to examine the Echo Web Framework and how images are used within it.

Image Basics

We should be all familiar with how images work in HTML.  You insert an image tag something like :

       <img src=”\imagepath\tree.gif” with=”10” height=”20>

and you get a 10x20 pixel image of a tree.  When the browser encountered the “img tag src attribute” it performs another HTTP request to get the image data, in this case from \imagepath\tree.gif.

Well guess what?  It work exactly the same way in the Echo Web Framework.  But Echo does have some more powerful features which will examine later.  But first lets do the basics.

The first image class you will most likely encounter is nextapp.echo.HttpImageReference.  This works just like “img tag src attribute” show above.  It indicates where a given image is to be found on the web server and what its dimensions are (if any).  You would use as follows

       HttpImageReference icon = new HttpImageReference(“imagepath\tree.gif”,10,20);

The image itself is usually served up via standard web server functions, mostly likely from a file on the web server. 

The HttpImageReference  class implements the nextapp.echo.ImageReference interface.  This is the root interface for all image classes within Echo.

Notice however that the class itself does not “display” an image but rather is used to indicate the URI to the image data.  This is true of all the Echo image classes.  They are “references” to images, hence the name ImageReference.

Other component will take this image references and use them to render images on the browser.  For example nextapp.echo.Button has an “icon” property that is a reference to an image, ie an ImageReference.  You can provide a HttpImageReference object or any one of the other classes that implement ImageReference.

Another useful image class is nextapp.echo.ResourceImageReference.  This class will reference image data inside you class path as a “resource” rather than from the web server path.  This is great because it allows you to “package” images alongside your the classes that use those images. 

The EchoPoint library uses ResourceImageReference a lot to provide images that are integral to how a component looks and acts.  For example the echopoint.TitleBar class uses this to provide its default “toggle” image.  The default image is stored with the class as a resource file.

Dynamic Images

The other image class of note is nextapp.echo.AwtImageReference.  Now this class is a doozy.  This class allows you to “dynamically paint” onto a java.awt.Image buffer and this will then be rendered into a PNG image ready to be served up to the browser.

This is great stuff and a huge step up from standard old HTML IMG tags.  This allows for truly dynamic images because they are derived from Java code.

For example the echopoint.ChartPanel component uses an AwtImageReference to render a chart image back to the browser.  What is actually does under the covers is allow you to use the excellent org.jfree.JFreeChart libraries to generate dynamic charts, which can be output to a java.awt.Image.  This is then placed inside an AwtImageReference object and then rendered back to the browser. 

Fantastic stuff.  The echopoint.ProgressBar, echopoint.Tachometer and echopoint.Thermometer all use the dynamic image capability to provide rich looking images.

There are some “gotchas” to look out for  when working with AwtImageReference. 

First off the java.awt.Image is a buffer of image data.  Therefore it takes up some memory.  Depending on its color depth and dimensions, this could be quite large, perhaps even into the megabytes.  By default AwtImageReference “caches” the java.awt.Image and returns it when required, hence memory is consumed for each AwtImageReference object used.

You can derive your own class from AwtImageReference in order to stop this caching.  Simply create your new class and override the getImage() method.  Now everytime getImage() is called you can “draw” the AWT image required and avoid the memory overhead. 

Of course this is a trade off between memory used and image processing required.  But isn’t it always?

The other “gotcha” is knowing when the underlying java.awt.Image has changed.  By default you will need to instantiate a new AwtImageReference if the underlying image changes.  This is because the AwtImageReference class is designed as an immtuable class.  Again overriding the getImage() method is one way around this.

Another good image class is the abstract nextapp.echo.StreamImageReference.  This class requires the implementing class provide two things.  A string indicating a valid RFC 1521 content type, such as image/png or image/gif, as well as a method to “render” an output stream of image data. 

This class therefore allows you to render your own image data.  You could, for example, use this to render images that are contained in a database or other exotic locatrion.

Image Listeners

The ImageReference interface has an update() for telling other classes that an image has changed.  When this is called, the implementing class is expected to inform all nextapp.echo.event.ImageUpdateListeners that the image has changed.  This is really useful on dynamic images references such as AwtImageReference.   The image can be repainted and then all interested ImageUpdateListeners are informed that it has changed.  They will take some action, like redisplaying themselves, for this image update.

Image Peers

In the same way components have component peers, ImageReference’s have ImagePeer’s. 

The image peer is responsible for actually “rendering” the image data to the browser.  In the case of HttpImageReference, the image peer simply returns the URI of the image.

But for something more complicated, like AwtImageReference, the image peer encodes the java.awt.Image data into a PNG output stream and sends that back to the browseras a special dynamic URI.

In the case of StreamImageReference, the image peer calls back the StreamImageReference to provide both the content type and an output stream of data, via the StreamImageReference.render() method.

Image Peers are created using a standard factory method and you will most likely not have to worry about creating your own Image Peer classes.

Component Peers and Images

When a component peer needs to render an image it should to do a few code housekeeping things. 

Firstly is should use an instance of nextapp.echoservlet.image.ImageManager to "manage the images" associated with the component.  This helper class will create "ImagePeers" for a given ImageReference, hence relieving the component peer from having to worry about this.  It also can return the URI of an ImagePeer so it can be embedded into the peer's HMTL output.

You only need one instance of ImageManager for a given component peer instance.  However you need to come up with a "unique name" for each image that the image manager is handling.  You need to place each "image" into the ImageManager when first starting or whenever an image property changes like :

/**
* @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent e) {
   redraw();
   ImageMap im = (ImageMap) getComponent();
   if (ImageMap.IMAGE_CHANGED_PROPERTY.equals(e.getPropertyName())) {
      getImageManager().setImage(IMAGE_ID, im.getImage());
   }
}

Also the ComponentPeer should declare itself as implementing an ImageUpdateListener so it can "listen" for when images have changed.  For example :

public class ImageMapUI extends EchoPointPeer implements ClientActionProducer, PropertyChangeListener, ImageUpdateListener {

It will typically "redraw" itself when an image has changed so the code is simple :

/**
* @see nextapp.echo.event.ImageUpdateListener#imageUpdate(nextapp.echo.event.ImageUpdateEvent)
*/
public void imageUpdate(ImageUpdateEvent e) {
   redraw();
}

EchoPoint Image Classes

There are a number of image-related classes in EchoPoint.  These classes build upon the image framework of Echo.  The first you will want to get familiar with is echopoint.image.ImageKit.  This class has a number of static methods for performing image manipulation, such as loading image data from a file or local URL, converting standard Java images into Java2D BufferedImages or making certain colors in an image transparent.

echopoint.image.EncodedImageReference is much like the standard AwtImageReference  except that it allows for an encoding scheme other than PNG.  It has a GIF encoder support as well as new replacement PNG encoder.  Otherwise it acts just like an AwtImageReference whereby you provide a java.awt.Image and it is encoded as a byte stream in a specific image format.

echopoint.image.TextImageReference  is a really useful class.  It allows you to specify a "background" java.awt.Image that can then be have text "dynamically written" upon it.  This is very useful for creating dynamic "buttons".  You do this by having a blank "button-like" background image, then specifing what text you want to "write" on this blank image.

TextImageReference will also allow you to "scale" the background image to fit the text you have used.  For example if you use a large font or carriage returns in the text, the background image can be "scaled" up to fit the dynamic text.  A number of different "scaling" algorithms are provided.  The horizontal and vertical splice algorithmns are expecially useful for "dynamic button scaling".

You use TextImageReference something like this :

java.awt.Image buttonBackgroundImage = ImageKit.loadCachedImage("/images/buttonTemplate.gif");

java.text.AttributedString as = TextImageReference.getAttributedString("Dynamic Tension!",Color.BLUE,new Font(Font.TIMES_NEW_ROMAN,Font.BOLD,12));

TextImageReference imageRef = new TextImageReference(as,buttonBackgroundImage);
imageRef.setInsets(new Insets(5));
imageRef.setScaleOption(TextImageReference.SCALE_SPLICE_V_THEN_H);

The text on the TextImageReference  is provided by a java.text.AttributedString.  This class alows you to "embed" presentation attributes, such as font and color, into a string of characters.  This allows you to have say the first character in "red Arial 24", while the rest of the string is in "black Verdana 12".  In the above exmaple it has the whole text in blue while a time new roman bold 12 point font is used.

In the above example if the text , "Dynamic Tension", is too large to fit within the background image, taking into account the Insets and the Fonts used, then the background image will be scaled so that the text will fit.

AttributedString also allows the special Unicode replacement character u'FFFC' to be replaced with java.awt.Image objects.  This will allow you to "embed" icon images inside you text string.  Pretty cool hey!

There is also a nextapp.echo.ResourceImageReference equivalent called echopoint.image.URLResourceImage.  It allows you to load any URL as an image.  This is handy if you have located the image resource using one of the resource loading techniques described here.


Home

SourceForge Logo

The EchoPoint project is kindly hosted by SourceForge