Java image resizer servlet
I'm working on a photo gallery application running on Java 6 using Tomcat 6, JQuery for the client side, and images and xml generated from Picasa. I needed several sizes of images for thumbnails and animations and I wasn't about to create multiple image sizes with Fireworks (I'm a lazy developer). Doing what every lazy developer does, I search Google for an image resize solution that would run on the application server and give me the sizes that I needed and take the manual work out of the equation. I found several PHP examples and disjointed Java examples, but no complete solutions. So, unfortunately I had to do some work to put something together.
Down to brass tax, here's the image resizer servlet code: (copy paste, use as you please)
package com.photo.gallery;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ImageResizer extends HttpServlet {
/**
* Servlet resizes an image located in a directory in a web project ex.
* /image?root=/albums&file=/thumbs/imagename.jpg&width=270&height=100 ex.
* /image?file=/thumbs/imagename.jpg&width=270 (default root, calculated
* height)
*/
private static final long serialVersionUID = -8285774993751841288L;
public void doGet(HttpServletRequest request, HttpServletResponse response) {
// Optional: Only supports output of jpg and png, defaults to png if not
// specified
String imageOutput = getParam(request, "output", "png");
// Optional: Folder in web app where images are located, defaults to
// albums if not specified
String imageRoot = getParam(request, "root", "/albums");
// Required: Path from root to image, including filename
String imageFile = getParam(request, "file", "/Album1/image1.jpg");
// Required: Width image should be resized to
int width = Integer.parseInt(getParam(request, "width", "250"));
// Optional: If specified used, otherwise proportions are calculated
int height = Integer.parseInt(getParam(request, "width", "0"));
// Set the mime type of the image
if ("png".equals(imageOutput))
response.setContentType("image/png");
else
response.setContentType("image/jpeg");
// Server Location of the image
String imageLoc = request.getSession().getServletContext().getRealPath(imageRoot) + imageFile;
try {
// Read the original image from the Server Location
BufferedImage bufferedImage = ImageIO.read(new File(imageLoc));
// Calculate the new Height if not specified
int calcHeight = height > 0 ? height : (width * bufferedImage.getHeight() / bufferedImage.getWidth());
// Write the image
ImageIO.write(createResizedCopy(bufferedImage, width, calcHeight), imageOutput, response.getOutputStream());
} catch (Exception e) {
log("Problem with image: " + imageLoc + e);
}
}
BufferedImage createResizedCopy(Image originalImage, int scaledWidth, int scaledHeight) {
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaledBI.createGraphics();
g.setComposite(AlphaComposite.Src);
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
// Check the param if it's not present return the default
private String getParam(HttpServletRequest request, String param, String def) {
String parameter = request.getParameter(param);
if (parameter == null || "".equals(parameter)) {
return def;
} else {
return parameter;
}
}
}
Here's the web.xml servlet definition and mapping:
image com.photo.gallery.ImageResizer 1 image /image
Images in html would look something like this:
Hopefully I've contributed something useful to another lazy developer and this solution works. I have no idea how scalable this solution is, nor do I care, it's just for a photo album where I needed cleanly resized images. More articles to come later on the album such as customizing and parsing xml from Picasa and a Java-based Ajax photo gallery using JQuery UI, don't hold your breath though, remember I'm lazy.
December 20th, 2007 - 19:46
Pretty cool. I would have separated the image resizing code from the servlet but, it would make posting on a web site a bit more of a pain. Anyway, your code is definitely clear enough to modify.
Kudo
Though not for the server, I did something similar with a bash script for my personal images (which are then loaded up on the server).
http://willcode4beer.com/tips.jsp?set=photoscript
It requires the ImageMagick libs be installed but, most Linux distros have ‘em by default anyway.
December 20th, 2007 - 21:03
Please have a look at SwingX lib for high quality image scaling scaling (http://www.swinglabs.org) and in particular this method:
GraphicsUtilities.createThumbnail(BufferedImage image, int newSize)
December 20th, 2007 - 22:57
Cool, thanks for the feedback. I used a servlet since I’m working on a dynamic photo gallery and need several different sized images for animations and such and wanted the least painful way to get any size at any point time from the original image. This just worked well for this application.
December 21st, 2007 - 03:36
check out this also: http://www.servletsuite.com/servlets/imagescale.htm
and
http://www.servletsuite.com/servlets/drawtext.htm
January 8th, 2008 - 10:32
Hi, Rob
I tried the SwingX lib, the image quality gets improved. But for some reason the created image has a smaller image inside the bigger one.
It is strange.
Thx
January 8th, 2008 - 10:35
Hi, Bob
GraphicsUtilities.createThumbnail created duplicate images, but GraphicsUtilities.createThumbnailFast works perfect and quality is good.
Thx
Fei
May 12th, 2008 - 02:42
Image resizing is an expensive task. Make some stress tests to your application and you will see the poor performance.
Anyway your solution could be easily tuned up by making good usage of http response headers and even including an intermediate cache
May 12th, 2008 - 07:28
You’re absolutely right Nacho! I’ve seen the performance implications of resizing on the fly. Good suggestions, it’s definitely not viable with a large number of requests in this example. My original implementation of this servlet was to resize and compress files on upload for content management, I had issue with users that loved to upload 2MB photos for display on their websites and the Java API compressed nicely without too much quality loss.
May 23rd, 2008 - 14:17
Hi webguy
My server still runs Java 1.4.3
Will this servlet run on it?
If not, what parts won’t and is there a work-around?
Any advice would be much appreciated.
May 24th, 2008 - 12:04
Lyndon, I think you’re good to go, all of these API’s were introduced in the 1.4 JDK. Just be aware this is probably not a scalable solution, some sort of disk caching would probably be needed in a high-scale environment since resizing images on the fly is a CPU intensive process.
August 5th, 2008 - 05:09
Thanks,
Nice example
September 14th, 2008 - 09:04
thanks man
October 30th, 2008 - 16:29
This is very cool. I would like to use it for allowing clietns to upload images to the server but I want them to resize the images on their end first.
February 6th, 2009 - 11:39
Hi webguy
I am looking for a way to get the pics uploaded before they hit the browser in the for of an application attached to my site. Once this happens it can then be sent to the browser and into the server as its the slow browser thats hurting me as internet speed of clients is quite low.
Is there an application that can be modified.
March 4th, 2009 - 14:37
Hoping someone has some thoughts on this. I have code below that is manipulating the image size similarly. We have upgraded java from JDK1.4.2_13 to JDK1.6.0_10. I am getting this error, but what is weird, is this same code worked fine under 1.4.2. I find that if I set a break point in the scaleImage method at the line where resizedImage is created (Image resizedImage = Toolkit.getDefaultToolkit()….) and let 30-45 seconds go by before resuming, everything works fine. If I let it run with no break points, this line:
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null),BufferedImage.TYPE_INT_RGB);
…fails because image.getWidth(null) and getHeight(null) are returning -1. Did anything change in JDK 1.6?
Thanks for any input!
Here is the stack trace:
java.lang.IllegalArgumentException: Width (-1) and height (-1) cannot be <= 0
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:999)
at java.awt.image.BufferedImage.(BufferedImage.java:312)
at strata.ws.ImageImportServlet.toBufferedImage(Unknown Source)
at strata.ws.ImageImportServlet.scaleImage(Unknown Source)
at strata.ws.ImageImportServlet.processRequest(Unknown Source)
at strata.ws.ImageImportServlet.doPost(Unknown Source)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
{code}private BufferedImage scaleImage(Image sourceImage, int width, int height)
{
ImageFilter filter = new ReplicateScaleFilter(width,height);
ImageProducer producer = new FilteredImageSource
(sourceImage.getSource(),filter);
Image resizedImage = Toolkit.getDefaultToolkit().createImage(producer);
return this.toBufferedImage(resizedImage);
}
private BufferedImage toBufferedImage(Image image)
{
image = new ImageIcon(image).getImage();
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.createGraphics();
g.setColor(Color.white);
g.fillRect(0,0,image.getWidth(null),image.getHeight(null));
g.drawImage(image,0,0,null);
g.dispose();
return bufferedImage;
}{code}
July 13th, 2009 - 20:58
Thanks! I was looking for this. I’ll need to modify it so that the default dimensions is just the original image’s default dimensions. This code is great for java/servlet based mobile WAP sites. But yeah, echo’ing the previous comments… this code is easy to follow.
September 1st, 2009 - 10:39
Thanks, its working! Will use on my website.
January 5th, 2010 - 11:02
Hai
I was looking some code like this itself for resizing images on load. But its not wokring for me, it does not show any error, it loads up but does not show image.
I have checked most of the things, its good. But when i went to view source from firefox and clicked the src of the image, it gave below error.
“The requested resource (/image) is not available.”
Waiting for the replies.
Thank you.
Kirun
January 5th, 2010 - 11:09
It’s a little difficult to debug without any details. Is your servlet set up correctly, did you include the appropriate querystring parameters after /image? Is your webapp setup to run at a root context? There are some details that aren’t included in this article, like the rest of the web.xml.
January 5th, 2010 - 12:04
Thank you for fast response.
Yes, my servlet is setup correctly. Using Netbeans IDE to develop, i have created simple java web application project in it to test this sevlet.
image
SERVLET.ImageResizer
1
image
/image
30
index.jsp
yes web application is set to run in root context. I have just changed the folder names to different. like /Albums refers to /Images i have changed in the servlet code and even while calling.
I think its not invoking Servlet from img tag. I have JDK 1.6 and Tomcat 6.
Your feedback will be help ful.
January 5th, 2010 - 12:43
Are you running in a Linux or Windows environment? What exactly did you include in the src attribute of the img tag?
January 7th, 2010 - 10:19
Hi WebGuy,
I got it to work that day itself. Thank you for that.
I changed the way i was invoking the servlet.
First i used this way, it did not work.
Below worked for me.
But i did not understand why the earlier code did not work.
Another one query, i have is, the resizing of image is reducing the quality of image a lot. Is there anyway we can make not to degrade the quality so much.
Thank you for the code, it was helpful.
January 27th, 2010 - 15:16
Hi everyone!!
How can I pass more than one parameter to a servlet??
I’m using JDeveloper, and I need to pass several parameters to an image component, wich load de image from data base using a servlet.
If can any one helme I will apreciate. Thanks
July 11th, 2010 - 15:21
Hey man! Thanks for the code, it was really helpful. But I found one small bug here. It’s at line #35:
int height = Integer.parseInt(getParam(request, “width”, “0″));
Please change “width” to “height” since it’s not good to read “width” parameter two times in a row!
December 29th, 2010 - 22:59
Its wonderful. this is exactly what I needed.
thanks a lot lolx….