JDK 1.2 is a major upgrade for the Java platform. It officially introduces Swing, the advanced widget library. It also adds support for CORBA, the standard object-oriented middleware protocol, and it defines a new API for graphics, Java 2D, as well as many, many other enhancements.
Buried in all these novelties is a JPEG codec. As the name implies, a JPEG codec encodes bitmaps as JPEG files. Java could read JPEG or GIF files since the early JDK days, but there was no built-in method to save bitmaps — until now.
The ability to save bitmaps is not only important for graphics applications. Any application that prepares data for publishing on the Internet will benefit from the JPEG codec. However, servlets will benefit the most.
Servlets
Servlets are server-side Java applications, a Java replacement for CGI scripts. Of course, servlets are portable; and thanks to a more efficient invocation mechanism, they are also dramatically faster than the old scripts.
Servlets are typically used with HTML forms. However, this is not a limitation. Servlets can be used to dynamically create files of any type: HTML, JPEG, GIF, XML, and so forth. In fact, there are many applications where you want to dynamically create graphics: hit counters, business charts, electronic postcards or to nicely present data, such as a game score.
The JPEG codec
The JPEG codec is in the com.sun.image.codec.jpeg package, i.e., not in a standard package (java or javax). It is expected, though, that a similar class will be available in the JDK of other vendors. It is also expected that a standard API will eventually include a JPEG codec.
Writing a JPEG from Java is easy, as illustrated by listing 1. First, create a JPEG codec, set some parameters and call
encode()
. The codec expects a BufferedImage object (which inherits from the familiar Image class) as input and writes the result in an OutputStream.
The application controls the quality of the image though parameters. Unlike GIF, JPEG is lousy at encoding, i.e., it will degrade the image to achieve better compression. The quality ratio determines how much degradation is acceptable. Unfortunately, one has to choose between the quality of the image and its size. The smaller the image, the lower the quality. Common values for the quality ratio are: 1.0 for no degradation, 0.75 for high quality images, 0.5 for medium quality, and 0.25 for very high compression with low-quality images. Although 0.75 is most commonly used, the correct ratio depends on the application’s needs.
Listing 1: Encoding BufferedImage in JPEG
public void encode(BufferedImage img,
OutputStream out)
throws IOException
{
JPEGImageEncoder encoder =
JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param =
encoder.getDefaultJPEGEncodeParam(img);
param.setQuality(0.75f,true);
encoder.encode(img,param);
}
A hit counter
Let’s wrap this up in a real application by writing our own hit counter as a Java servlet. Listing 2 is the WebCounter servlet. The servlet has been tested under JDK 1.2 RC1 with JSDK 2.0 (the servlet development kit).
A servlet inherits from HttpServlet. The Web server calls the doGet()
method when it receives a GET request from a Web browser (other methods exist for POST and PUT requests). The init()
and destroy()
methods are called, respectively, when the servlet is loaded and unloaded. For more information on servlets, check the Resources section below.
The interesting code is in doGet()
, which first set the content type to “image/jpeg” to signal that it will return an image. Next, it draws the counter and uses the JPEG codec to send the result, as a JPEG image, to the server.
The drawing code uses the new Java 2D API, which is an extension of AWT and, therefore, should be familiar to Java programmers. A new class, Graphics2D, adds new methods to the familiar AWT Graphics. When running under JDK 1.2, an application should use Graphics2D where it formerly used Graphics.
One of the new methods is setRenderingHint()
, which controls graphics rendering. The servlet turns on anti-aliasing. This smoothes curves, which results in less-sharp, more-pleasant graphics.
The servlet also uses the new TextLayout class for finer control over the placement of text.
Listing 2: The WebCounter servlet
package com.psol.author;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.image.*;
import com.sun.image.codec.jpeg.*;
public class WebCounter extends HttpServlet
{
protected int count = 0;
protected final static int WIDTH = 50,
HEIGHT = 18,
FONTSIZE = 14;
protected final static String FONTNAME = “Arial”,
FILENAME = “webcounter.data”;
public void init(ServletConfig config)
throws ServletException
{
super.init(config);
try
{
DataInputStream in =
new DataInputStream(
new FileInputStream(FILENAME));
count = in.readInt();
}
catch(IOException x)
{}
}
public void destroy()
{
try
{
DataOutputStream out =
new DataOutputStream(
new FileOutputStream(FILENAME));
out.writeInt(count);
}
catch(IOException x)
{}
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType(“image/jpeg”);
BufferedImage img = draw(Integer.toString(++count));
OutputStream out = response.getOutputStream();
JPEGImageEncoder encoder =
JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param =
encoder.getDefaultJPEGEncodeParam(img);
param.setQuality(1.0f,true);
encoder.encode(img,param);
out.close();
}
protected BufferedImage draw(String st)
{
BufferedImage img =
new BufferedImage(WIDTH,HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.orange);
g2.clearRect(0,0,WIDTH,HEIGHT);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.black);
Font font = new Font(FONTNAME,Font.PLAIN,FONTSIZE);
g2.setFont(font);
TextLayout tl =
new TextLayout(st,font,
g2.getFontRenderContext());
Rectangle2D r = tl.getBounds();
// center the text
tl.draw(g2,(float)((WIDTH – r.getWidth()) / 2),
(float)(((HEIGHT – r.getHeight()) / 2) +
r.getHeight()));
g2.dispose();
return img;
}
public String getServletInfo()
{
return “WebCounter by B. Marchal for developer.com”;
}
}
Conclusion
Thanks to the JPEG codec in JDK 1.2, it is easy for Java applications, servlets, or applets to create JPEG files. All applications that create Internet files will benefit from the ability to save JPEG files. The new codec is particularly interesting in combination with servlets for generating graphics on demand for business (e.g., charts) or fun (e.g., a hit counter).
Resources
- NO HEADLINE
- New Features in JDK 1.2
- A new home for Java — servlets
- Dynamic Web Pages in Java with Servlets
About the author
Benoît Marchal runs his own consulting company, Pineapplesoft. His interests include distributed applications, object-oriented programming and design, system programming, hand-helds, and computer languages (notably, Java). He also enjoys teaching and writing. You can contact him at bmarchal@pineapplesoft.com.