Dynamic graphics in Java servlets

Lecture




    How to create a graphical hit counter? A diagram depicting the workload of the channel to the provider or the number of letters in the queue? In short, how to form an image dynamically at the request of the user? In his article, Ken McCrary offers solutions for this task. (2500 words)
Graphs and charts make it easier to understand analytical information. Imagine, for example, a table of measurements of the parameters of the channel load, conducted every five minutes. It's hard to believe that you have the patience to look at it at least once a week. Whereas, the corresponding diagram seems to be quite digestible and comprehensive. In many cases, images must be created in real time at the request of the user. The need for this may be due to the nature of the displayed data, in the case when the data is received continuously or changes over time, or the ability to significantly reduce the used disk space. Of course, it is not always appropriate (technically feasible) to construct images dynamically, but, where it is really necessary, the use of successful technological solutions can lead to a significant gain in productivity and quality of service.

Reading and writing images, JDK requirements

In order for a servlet — an application running on a server that processes user requests — to dynamically create images, first of all, a mechanism is needed to read and write graphic files. More precisely, the servlet should be able to send the resulting image in response to a user request. The core libraries (Core API) for Java do not provide the means by which one could save the resulting image in one of the graphic formats. There are Sun libraries for Java 1.1 and Sun licensed libraries for Java 1.2. Since they are located in the com.sun package, they do not belong to either the main libraries or the standard extensions, so applications using them cannot be considered portable. In other words, they may not work on a virtual machine released by another company. It is worth noting that the approved Java Specification Request JSR-000015 for the standard Java 2 extension contains a description of the mechanism for reading and writing graphic files; when it is implemented, it will be possible to write portable programs that perform image input / output.

For this article, I have prepared examples that work on the Java 1.1 and Java 1.2 platforms.

Image Formats

GIF is the most common format for image files on the Web. It is widely supported by browsers, including the very first. Unfortunately, writing programs that generate images in this format is potentially hampered by a patent for a data compression algorithm. The programs in this article create images in jpeg and png format. The JPEG format is chosen primarily from those considerations that the implementation of Sun Java 1.2 allows you to generate images of this type without the use of additional libraries. (In the sample application for JDK 1.1, you can get a file not only in PNG format, but also in many others, including JPEG and GIF — approx. Translator) One of the differences between JPEG and GIF formats is that the data compression algorithm used in GIF, in contrast to the algorithm used in JPEG, does not distort the image. Usually, artifacts in JPEG images are not very noticeable. (It should be noted that the JPEG format copes better with the presentation of photographs, rather than text, diagrams or images containing thin lines and clear color transition boundaries - for example, a translator) The second example uses the PNG format with a compression algorithm without data loss and, moreover, free from legal difficulties.

Servlet Architecture

We divide our program into two parts. The first part, the servlet, is responsible for processing the HTTP request and returns the requested image to the client, if possible. The second part, the class that forms the picture. For ease of implementation, the name of the class being used will be passed as a parameter when accessing the servlet. The corresponding Java class must implement a specific interface for communicating with the servlet. We give a description of this interface:
  public interface ImageProducer {
         / **
          * MIME type of image being created.
          *
          * @return MIME image type.
          * /
         public String getMIMEType ();
         / **
          * Creates an image and writes it to the specified stream.
          *
          * @param stream Where to write the picture.
          * /
         public void createImage (OutputStream stream )
                  throws IOException;
 }
The ImageProducer interface contains a method for determining the type of image and a method for forming an image. The resulting picture is sent to the client.

The following code demonstrates how a servlet works with classes that implement the ImageProducer interface:

  ImageProducer imageProducer =
         (ImageProducer)
      Class.forName (request.getQueryString ()). NewInstance (); 
  response.setContentType (imageProducer.getMIMEType ()); 
  imageProducer.createImage (response.getOutputStream ());
The servlet creates (loads) a class with the name specified in the request parameters - part of the URL to the right after the "?". The resulting class is cast to the ImageProducer type. Then, referring to the appropriate methods, the servlet gets the type and forms the image. If there are no errors, the picture is sent to the client. The code above can cause several exceptions, the most common are ClassNotFoundException and ClassCastException. The first is because the class whose name is passed as a request parameter is not available to the loader (ClassLoader), and the second because the specified class does not implement the ImageProducer interface. In case of an error, the client, of course, does not receive a picture, and the browser displays an image indicating that the server did not respond to the request. The program was tested using the Java Server Web Development Kit (JSWDK 1.0.1), but you should get similar results on most other Web servers that support Java.

Image Creation in Java 1.1

For my first example, I prepared code that will work on the Java 1.1 platform. Although JVM 1.2 virtual machines are fairly common, not everyone can host programs on this platform. Unfortunately, providers do not rush to update virtual machines on their servers. As a result, you have to develop servlets running on the Java 1.1 platform. This does not greatly complicate the task; Nevertheless, there are some difficulties associated with the formation of images, which we will discuss below. We will build a pie chart, which we, for the sake of completeness, will color and sign. The chart will show the drinks used by software developers. Let's see how to do it. For image I / O operations in Java 1.1, Sun offers the Jimi library. Sun purchased it from a small company. Before starting to distribute this library, Sun transferred classes to the com.sun package, but otherwise did not change anything.

The following steps need to be done to form a PNG image using Jimi.

  1. Create an application window (Frame for image acquisition.
  2. I use the AWT image to create an implementation of the Graphics class.
  3. Draw a picture using the Graphics object.
  4. Create a JimiWriter object based on the flow of data sent to the client.
  5. Convert the image to the appropriate format and send it to the client.
To generate and modify images on the Java 1.1 platform, you must use the active AWT component. As a rule, a servlet should not create AWT components that are commonly used in GUI applications. In this case, you need a graphic (AWT) object in order to get an object of the Graphics class, with which you can draw new pictures. You have to put up with a small window on the console of the Web server. If you know how to create images in Java 1.1 without using the AWT component, please let me know. One of the possible options is to load a previously prepared template from the server disk, for example, using the java.awt.Toolkit.createImage () method. After you create an AWT image, you can get an implementation of the Graphics class and use it for drawing. With the Graphics object at your disposal, you can close an unnecessary window on the server console. I will leave this experiment to interested readers. Remember, the servlet uses the ImageProducer interface to communicate with the class that draws the pie chart. Therefore, our JIMIProducer class must implement this interface. First of all, create an AWT window, AWT images, and finally a Graphics object:
  Frame f = new Frame ();
         f.setVisible ( true ; 
          image = f.createImage (ImageWidth, ImageHeight); 
          graphics = image.getGraphics (); 
          f.setVisible ( false );
The key method of the JIMIProducer class is drawSlice. Receiving at the input a label and the size of a segment in degrees, this method draws a segment of the diagram, paints it and signs it. Next, I will explain in more detail how this happens. We will fill the "insides" of the diagram in a clockwise direction, starting from the "three o'clock" position, that is, we will draw the first line from the center to the circle of the bounding diagram in the clockwise position at three o'clock in the afternoon (or nights, as you like more). Step back clockwise to the required number of degrees and draw a second line bounding the chart segment. And so on. The following code gets the input value of the segment in degrees and draws the border of this segment. It is called sequentially for all segments, and it is assumed that the total angular values ​​will be 360 ​​degrees.
  // ************************************************ *
         // Convert Angle To Radians
         // 1 degree = pi / 180 rad
         // ************************************************ *
         double theta = degrees * (3.14 / 180); 
          currentTheta + = theta;
         // ************************************************ *
         // Translate to Cartesian coordinates
         // x = r cos @
         // y = r sin @
         // ************************************************ *
         double x = Radius * Math.cos (currentTheta);
         double y = Radius * Math.sin (currentTheta);
         Point mark2 = newPoint (center); 
          mark2.translate (( int ) x, ( int ) y); 
          graphics.drawLine 
                   (center.x, center.y, mark2.x, mark2.y);

Then, you need to color the diagram segments. To do this, you can use the very useful fillArc () method:

  graphics.setColor (colors [colorIndex ++]); 
          graphics.fillArc (Inset, 
                          Inset, 
                          PieWidth 
                          Piehight 
                          -1 * lastAngle, 
                          -1 * degrees);
The final task of the drawSlice () method is to draw segment labels. The location of the label is calculated based on the metric of the font used. The final version of the diagram can be seen in the figure.

  Dynamic graphics in Java servlets

Fig. 1. The final version of the pie chart. (Not all browsers show PNG files, so here we put the GIF file.)

Creating images in Java 1.2

Almost everyone is now interested in stock prices on the stock exchange. Let's draw (everyone for joy) on our chart the stock price of Sun for one of the weeks of March.

To create JPEG images, the com.sun.image.codec.jpeg.JPEGImageEncoder class is used. I repeat that belonging to the com.sun package means that this class is not part of the main API and all relevant warnings apply to it. The JPEGImageEncoder class "understands" how to transcode the java.awt.image.BufferedImage image, so we'll use it. To create the BufferedImage class, you need to specify the required image sizes. After creation, the BufferedImage class provides the ava.awt.Graphics2D class, which can be used to draw on the image corresponding to the BufferedImage class. Is everything simple? So, the basic steps necessary for the formation of images in JPEG format:
  1. Create a class JPEGImageEncoder, providing it with an OutputStream data stream transmitted to the client.
  2. Create a BufferedImage class of the required sizes.
  3. Use the Graphics2D class implementation provided by the BufferedImage class to draw the diagram.
  4. Using the JPEGImageEncoder class obtained earlier, we will encode the drawn image into JPEG format and write it to the stream sent to the client.

Let's discuss some drawing details using Graphics2D.

To create a stock price chart, you need to actually draw a few lines. The Java 2D package, java.awt.geom, contains all the necessary classes for this. The abstract class Line2D defines a line segment. It has two implementations that differ in the type of coordinates used. The class Line2D.Double applies the primitive type double, and the class Line2D.Float uses floating point real numbers. High accuracy is completely unnecessary for our schedule, but I will not save and create segments with the direct class Line2D.Double.

We will give, as an example, a program section that draws the horizontal axis of the chart:

  horAxis = new Line2D.Double (HorzInset, 
                          ImageHeight - VertInset, 
                          ImageWidth - HorzInset, 
                          ImageHeight - VertInset); 
          graphics.draw (horAxis);
The horizontal axis is constructed with a small indent from the border of the screen, providing a place for marking. After creation, you draw a line by calling on the draw () method of the Graphics2D object. Let me remind you that you got it from the implementation of the BufferedImage class. The Graphics2D class contains methods for drawing graphics primitives, more than enough for our purposes. Figure 2 shows the final version of the graph.

  Dynamic graphics in Java servlets

Fig. 2. The final version of the stock price chart.

Performance

Poor performance is one of the main accusations of opponents of Java. I do not share this position. I am convinced that you can achieve good performance for a program written in Java that dynamically creates images. As a software developer, I can give you advice: if you are not comfortable with performance, buy more advanced computers.

Conclusion

In this article, I showed you how to create simple images in Java programs, and used this technique to write a servlet that forms an image upon user request. This technology has a huge number of applications, limited, perhaps, beyond the imagination. Two questions should be kept in mind when developing applications based on the ideas outlined: the performance of the image creation algorithm and the limitation of the bandwidth of the server’s communication channel. To solve the latter problem, it is obviously necessary to reduce the size of the image as much as possible, in the first case, apply standard methods of application optimization.
created: 2014-10-09
updated: 2021-03-13
132547



Rating 9 of 10. count vote: 2
Are you satisfied?:



Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Object oriented programming

Terms: Object oriented programming