Site Network: Personal | Professional | Photography

Technical Blog

This blog will contain content related to Java, Seam, Security, my sites and projects, as well as other technical subjects I am interested in.

Comments and questions are welcome!

How To Resize Uploaded Images Using Java - Better Way

Thursday, March 13th, 2008

Based on helpful comments from Matt on this previous post:

How To Resize Uploaded Images Using Java

I have upgraded the image resizing code. The results are noticeably better in quality, even at thumbnail sizes. I wanted to share the completed new code, in case anyone needs it.

Again, thanks to Matt S. for his pointers.

 
    /**
     * The JAI.create action name for handling a stream.
     */
    private static final String JAI_STREAM_ACTION = "stream";
 
    /**
     * The JAI.create action name for handling a resizing using a subsample averaging technique.
     */
    private static final String JAI_SUBSAMPLE_AVERAGE_ACTION = "SubsampleAverage";
 
    /**
     * The JAI.create encoding format name for JPEG.
     */
    private static final String JAI_ENCODE_FORMAT_JPEG = "JPEG";
 
    /**
     * The JAI.create action name for encoding image data.
     */
    private static final String JAI_ENCODE_ACTION = "encode";
 
    /**
     * The http content type/mime-type for JPEG images.
     */
    private static final String JPEG_CONTENT_TYPE = "image/jpeg";
 
    private int mMaxWidth = 800;
 
    private int mMaxWidthThumbnail = 150;
 
.....
 
    /**
     * 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 image could not be manipulated correctly.
     */
    public byte[] resizeImageAsJPG(byte[] pImageData, int pMaxWidth) throws IOException {
	InputStream imageInputStream = new ByteArrayInputStream(pImageData);
	// read in the original image from an input stream
	SeekableStream seekableImageStream = SeekableStream.wrapInputStream(imageInputStream, true);
	RenderedOp originalImage = JAI.create(JAI_STREAM_ACTION, seekableImageStream);
	((OpImage) originalImage.getRendering()).setTileCache(null);
	int origImageWidth = originalImage.getWidth();
	// now resize the image
	double scale = 1.0;
	if (pMaxWidth > 0 && origImageWidth > pMaxWidth) {
	    scale = (double) pMaxWidth / originalImage.getWidth();
	}
	ParameterBlock paramBlock = new ParameterBlock();
	paramBlock.addSource(originalImage); // The source image
	paramBlock.add(scale); // The xScale
	paramBlock.add(scale); // The yScale
	paramBlock.add(0.0); // The x translation
	paramBlock.add(0.0); // The y translation
 
	RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_RENDERING,
		RenderingHints.VALUE_RENDER_QUALITY);
 
	RenderedOp resizedImage = JAI.create(JAI_SUBSAMPLE_AVERAGE_ACTION, paramBlock, qualityHints);
 
	// lastly, write the newly-resized image to an output stream, in a specific encoding
	ByteArrayOutputStream encoderOutputStream = new ByteArrayOutputStream();
	JAI.create(JAI_ENCODE_ACTION, resizedImage, encoderOutputStream, JAI_ENCODE_FORMAT_JPEG, null);
	// Export to Byte Array
	byte[] resizedImageByteArray = encoderOutputStream.toByteArray();
	return resizedImageByteArray;
    }
 

How To Resize Uploaded Images Using Java

Thursday, March 6th, 2008

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.

Constants

Tuesday, August 14th, 2007

What - constants in Java
While Java does not have a built-in Constant type, functionally constants are supported through the use of two modifiers: final and static, like this:

public static final int NUM_CARDS_IN_DECK=52;

First, we define the variable as public, this is not necessary for using the constant within the same class, but is needed in order to access the same constant from multiple classes. I will go into this distinction in more detail later.

Secondly we mark it as static. This provides two related features. The variable can be referenced without instantiating a copy of it’s enclosing object. The variable will only exist ONCE in memory. This is very efficient. Also, during compilation the access will be in-lined into the class and therefore much faster.

Thirdly we mark it as final. This prevents the value from being changed or overridden, ensuring that that the value is consistent throughout your entire application, and letting the compiler know it does not have to worry about the value changing.

From there it looks like a normal variable except for the name. The convention is to name constants in all capitals with underscore characters separating logical words.
(more...)