Skip to main content

Blarg #15: How can I do image processing on the server-side?

Posted by jfalkner on May 27, 2005 at 4:51 PM PDT

I met Fred and John and they asked about doing clever image manipulation on the client-side, but without requiring the client to run anything but a web browser. It seemed like doing a few tricks with ImageIO on the server-side would solve the problem, and it'd eliminate the piles of JScript they had been working on. Here is the code so that others can easily write servlets that manipulate and generate images. Nothing like a blog to make something Googleable.

The initial task seemed pretty straight forward. Documents are imaged and an algorithm picks out text from certain places in the document. Most of the time the text is recognized fine, but in the cases where it is not a user has to manually verify the value of the text. The webapp needs to show the entire document with the area of interest highlighted, the specific chunk of text being handled, and provide a way to give feedback.

The first servlet dynamically highlights an area on an existing image. It saves Fred and John from having to make multiple copies of their image, and it doesn't require anything but an image tag on the client-side.

Here is the interesting bit that highlights the image. The highlight is nothing more than a rectangle filled with a semi-transparent color....

		// read in the image
InputStream imageIn = this.getServletContext().getResourceAsStream(
"/images/" + imageID);
// buffer for speed
BufferedInputStream in = new BufferedInputStream(imageIn);

// check the cache, start with no image
BufferedImage bi = ImageIO.read(in);

// highlight the image
Graphics g = bi.getGraphics();
// highlight the area
g.setColor(new Color(1f, 0f, 0f, 0.5f));
g.fillRect(x, y, width, height);
// draw a box
g.setColor(Color.BLACK);
g.drawRect(x, y, width, height);

// set the response type
response.setContentType("image/jpeg");

// send the image straight to the client
ServletOutputStream out = response.getOutputStream();

// write the image as a png
ImageIO.write(bi, "JPEG", out);

Note that ImageIO and the Graphics object makes the task easy. ImageIO gives you a BufferedImage and Graphics lets you draw a semi-transparent color on it. The entire servlet code is in the "Extended Entry" section, a.k.a. the section that google probably won't see but that you can cut-and-paste from.

The second servlet is very similar, except it dynamically returns sub-sections of an existing image. This saves Fred and John the task of making many different little images that correspond to each interested section of a scanned document. Instead they can focus on describing those sections (x, y, width, height) in their database and rely on the servlet to dynamically generate appropriate images for a web browser.

		// read in the image
InputStream imageIn = this.getServletContext().getResourceAsStream(
"/images/" + imageID);
// buffer for speed
BufferedInputStream in = new BufferedInputStream(imageIn);

// check the cache, start with no image
BufferedImage bi = ImageIO.read(in);

// make the sub-image
BufferedImage subImage = bi.getSubimage(x1, y1, width, height);

// set the response type
response.setContentType("image/jpeg");

// send the image straight to the client
ServletOutputStream out = response.getOutputStream();

// write the image as a png
ImageIO.write(subImage, "JPEG", out);

Again, ImageIO and BufferedImage make the task easy. ImageIO gives the BufferedImage and the sub-image is made by invoking BufferedImage's getSubImage() method. The results are then serialized to the client as a JPEG. Full code is in the copy-and-paste section.

One final thing. The image and img HTML tags don't take well to passing URL parameters. That is why the servlets expect image names to be encoded as x-y-width-height-imagename, where everything but the dashes is replaced with appropriate values. On the server-side the URL is split up and the appropriate values are parsed. Check out the copy-and-paste section if you'd like to see the code.

Good luck Fred and John!

Jayson Falkner
jayson@jspinsider.com

Here is the image highlighting servlet:

/**
* This code is free for John and Fred to use as they please. Good luck with your JSP and Servlets.
*/
package jfalkner.imagemucking;

import java.io.IOException;

import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.imageio.*;
import java.awt.image.*;
import java.awt.*;

/**
* This is a servlet that will dynamically highlight chunks of an image.
*
* @author Jayson Falkner - jfalkner@umich.edu

*/
public class ImageHighlightServlet extends HttpServlet {

/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
*      javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {

// get the image
System.out.println(request.getRequestURI());
String[] uriSplit = request.getRequestURI().split("/");
// get the image name
String imageData = uriSplit[uriSplit.length - 1];
System.out.println(imageData);
// assume x-y-width-height-name
String[] parts = imageData.split("-");
// get the subimage coordinates
int x = Integer.parseInt(parts[0]);
int y = Integer.parseInt(parts[1]);
// get the bottom right coordinate
int width = Integer.parseInt(parts[2]);
int height = Integer.parseInt(parts[3]);
String imageID = parts[4];

// read in the image
InputStream imageIn = this.getServletContext().getResourceAsStream(
"/images/" + imageID);
// buffer for speed
BufferedInputStream in = new BufferedInputStream(imageIn);

// check the cache, start with no image
BufferedImage bi = ImageIO.read(in);

// highlight the image
Graphics g = bi.getGraphics();
// highlight the area
g.setColor(new Color(1f, 0f, 0f, 0.5f));
g.fillRect(x, y, width, height);
// draw a box
g.setColor(Color.BLACK);
g.drawRect(x, y, width, height);

// set the response type
response.setContentType("image/jpeg");

// send the image straight to the client
ServletOutputStream out = response.getOutputStream();

// write the image as a png
ImageIO.write(bi, "JPEG", out);

// flush/close resources
out.flush();
out.close();
}
}

And here is the sub-image making servlet:

/**
* This code is free for John and Fred to use as they please. Good luck with your JSP and Servlets.
*/
package jfalkner.imagemucking;

import java.io.IOException;

import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.imageio.*;
import java.awt.image.*;

/**
* This is a servlet that will dynamically return a subsection of an image.
*
* @author Jayson Falkner - jfalkner@umich.edu

*/
public class ImageServlet extends HttpServlet {
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
*      javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {

// get the image
System.out.println(request.getRequestURI());
String[] uriSplit = request.getRequestURI().split("/");
// get the image name
String imageData = uriSplit[uriSplit.length - 1];
System.out.println(imageData);
// assume x-y-width-height-name
String[] parts = imageData.split("-");
// get the subimage coordinates
int x1 = Integer.parseInt(parts[0]);
int y1 = Integer.parseInt(parts[1]);
// get the bottom right coordinate
int width = Integer.parseInt(parts[2]);
int height = Integer.parseInt(parts[3]);
String imageID = parts[4];

// read in the image
InputStream imageIn = this.getServletContext().getResourceAsStream(
"/images/" + imageID);
// buffer for speed
BufferedInputStream in = new BufferedInputStream(imageIn);

// check the cache, start with no image
BufferedImage bi = ImageIO.read(in);

// make the sub-image
BufferedImage subImage = bi.getSubimage(x1, y1, width, height);

// set the response type
response.setContentType("image/jpeg");

// send the image straight to the client
ServletOutputStream out = response.getOutputStream();

// write the image as a png
ImageIO.write(subImage, "JPEG", out);

// flush/close resources
out.flush();
out.close();
}
}
Related Topics >>

Comments

How to call it in the browser

Hello, First of all , thank you for your source it's verry iteresting. I want to call it whitout showing the name of directory in the browser , so i do this in the web.xml file: ImageHighlightServlet servlet.ImageHighlightServlet dir D:/Tomcat 6.0/webapps/Projet/Upload and then the mapping. Thanks in advance. Best regards.