How To Resize Uploaded Images Using Java

Edit: please read the better way here: Better way to Resize Images Using Java!

———————–
I am building a Seam application which need to support users uploading images, and then the site displaying them. I wanted to resize big images into something reasonable (say 1024 or 800 px wide) and generate a thumbnail, and I also wanted to standardize on a single image format just to make things easy and consistent.

So I needed method that would take an uploaded image as a byte array (byte[]) and would resize the image (if needed) and convert it to a fixed quality JPG, and give me back a byte array to store in the database. I am using Seam, so I get a handy byte array, but this method should work fine for non-Seam applications as well.

    /**
     * This method takes in an image as a byte array (currently supports GIF, JPG, PNG and possibly other formats) and
     * resizes it to have a width no greater than the pMaxWidth parameter in pixels. It converts the image to a standard
     * quality JPG and returns the byte array of that JPG image.
     *
     * @param pImageData
     *                the image data.
     * @param pMaxWidth
     *                the max width in pixels, 0 means do not scale.
     * @return the resized JPG image.
     * @throws IOException
     *                 if the iamge could not be manipulated correctly.
     */
    public byte[] resizeImageAsJPG(byte[] pImageData, int pMaxWidth) throws IOException {
	// Create an ImageIcon from the image data
	ImageIcon imageIcon = new ImageIcon(pImageData);
	int width = imageIcon.getIconWidth();
	int height = imageIcon.getIconHeight();
	mLog.info("imageIcon width: #0  height: #1", width, height);
	// If the image is larger than the max width, we need to resize it
	if (pMaxWidth > 0 && width > pMaxWidth) {
	    // Determine the shrink ratio
	    double ratio = (double) pMaxWidth / imageIcon.getIconWidth();
	    mLog.info("resize ratio: #0", ratio);
	    height = (int) (imageIcon.getIconHeight() * ratio);
	    width = pMaxWidth;
	    mLog.info("imageIcon post scale width: #0  height: #1", width, height);
	}
	// Create a new empty image buffer to "draw" the resized image into
	BufferedImage bufferedResizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
	// Create a Graphics object to do the "drawing"
	Graphics2D g2d = bufferedResizedImage.createGraphics();
	g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
	// Draw the resized image
	g2d.drawImage(imageIcon.getImage(), 0, 0, width, height, null);
	g2d.dispose();
	// Now our buffered image is ready
	// Encode it as a JPEG
	ByteArrayOutputStream encoderOutputStream = new ByteArrayOutputStream();
	JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(encoderOutputStream);
	encoder.encode(bufferedResizedImage);
	byte[] resizedImageByteArray = encoderOutputStream.toByteArray();
	return resizedImageByteArray;
    }

In my application I call this method twice, once to convert the uploaded image into a limited size JPG, and then once again to generate a much smaller thumbnail. I store both of these in the database and will use caching at the Apache layer to ensure performance.

Quartz Scheduling and Seam (part 1)

I am working on a new application, which will require some scheduled jobs. I used EJB3 Timers in 10MinuteMail, but now Seam includes and uses Quartz, an open source scheduling system. So I figured I’d try the new hotness.

So far, it’s been a rough road, and I’m not 100% up and running yet (hence the part 1 in the title), but I wanted to share what I’ve learned along the way as the Seam documentation is lacking a lot of information (although some of what’s below mirrors the Seam documentation).

First you have to enable the Quartz engine for handling @Asynchronous methods. Add this line to your components.xml file:

<async:quartz -dispatcher />

I also found that I had to define the async namespace in my component.xml (generated by seam-gen from Seam 2.0 CR1):

xmlns:async="http://jboss.com/products/seam/async"

Then I set up my method:

@Asynchronous
public QuartzTriggerHandle scheduleSiteCheck(@Expiration
Date pWhen, @IntervalDuration
Long pInterval, Long pSiteId) {
Site site = (Site) entityManager.createQuery("from Site where id = :id").setParameter("id", pSiteId)
.getSingleResult();
checkSite(site);
return null;
}

Continue reading

CAPTCHA with Seam in Three Minutes

Adding a CAPTCHA to a form using Seam is easy now that Seam is bundling jCaptcha.

The Seam documentaiton is good, and can be found in section 13.9 here:

http://docs.jboss.com/seam/2.0.0.CR2/reference/en/html/security.html#d0e7755

If you used seam-gen to create your project, you will need to make a few changes.

First, you need to modify your project’s ant build script to deploy the captcha jar into your ear (or possibly .war). In the target “ear” of the build.xml file, you will find a list of many jar files being copied from your project’s lib directory into the ear. Simply add the captcha jar to that list, like this:

<include name="lib/jcaptcha-all-1.0-RC6.jar"></include>

Now that the jar is deploying, you need to reference it in the application.xml file found under your project’s resources/META-INF directory. Add this entry:

<module>
<ejb>lib/jcaptcha-all-1.0-RC6.jar</ejb>
</module>

If you used seam-gen you will find that the Seam Resource Servlet is already defined in your web.xml so the step defined in the documentation in section 13.9.1 is not necessary.

Continue reading