The Source for Java Technology Collaboration
User: Password:



Jayson Falkner

Jayson Falkner's Blog

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

Posted by jfalkner on May 27, 2005 at 04:51 PM | Comments (3)

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();
	}
}

Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Batik does SVG on the server

    Posted by: steltenpower on May 28, 2005 at 03:04 PM

  • There are a couple of taglibs in Coldtags suite. E.g.:
    http://www.servletsuite.com/servlets/jpegtag.htm

    Posted by: dnamiot on May 31, 2005 at 03:39 PM

  • Hi,
    I see the above code just sends a image file from one servlet to another but can anyone provide me code of how to send the same image from servlet to an applet at client side.

    Posted by: rsk2k3 on October 27, 2005 at 06:48 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds