How To Resize Uploaded Images Using Java

Home/Java, Seam/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.

By | 2017-05-18T15:18:14+00:00 March 6th, 2008|Java, Seam|26 Comments

About the Author:

26 Comments

  1. Matt Sidesinger March 13, 2008 at 7:36 am - Reply

    I have gotten better quality in the past when creating the BufferedImage with the following logic to perform the resize:

    import java.awt.RenderingHints;
    import javax.media.jai.RenderedOp;
    import javax.media.jai.operator.SubsampleAverageDescriptor;
    ...
    RenderingHints hints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    RenderedOp resizeOp = SubsampleAverageDescriptor.create(image, scale, scale, hints);
    BufferedImage bufferedResizedImage = resizeOp.getAsBufferedImage();
    
  2. Devon March 13, 2008 at 8:20 am - Reply

    Thank Matt, I will give that a try!

    — edit:

    How do you convert an incoming ImageIcon or Image to a RenderedImage needed for the SubsampleAverageDescriptor.create() call? I can see how to do it if I go through the process of painting it full size into a another BufferedImage, but that seems like it would make this call at least 2X as computationally expensive..

  3. Devon March 13, 2008 at 8:43 am - Reply

    Or did you mean just use the rendering hints you have there, and leave the rest of the code alone? Does the SubsampleAverageDescriptor provide superior resizing?

  4. Matt Sidesinger March 13, 2008 at 12:08 pm - Reply

    Sorry about the not including anything about how to get a RenderedImage as I am not using an ImageIcon. A BufferedImage implements RenderedImage. You can creaete a BufferedImage from a byte[] by creating a ByteArrayInputStream and passing it to ImageIO.read().

    This post shows visual results of resizing with and without using SubsampleAverage: https://www.i-proving.ca/space/Technologies/Java+Advanced+Imaging

    I was experiencing similar results where edges were not smooth.

  5. […] How To Resize Uploaded Images Using Java […]

  6. Doug May 30, 2008 at 10:45 am - Reply

    I was wondering if anyone else was getting weird behavior doing this sort of thing on Mac OSX. I am using the code above to create a thumbnail and when the code is executed the org.apache.catalina.startup.Bootstrap process shows up on the menu bar at the top of my screen. This occurs on both Tiger and Leapord. On Tiger you can shutdown the machine and the machine stops the apache process and shuts down. On Leapord the machine does not shut down until the user chooses to quit org.apache.catalina.startup.Bootstrap manually. I really need to be able to size images but I can not expect my user base to manually quit org.apache.catalina.startup.Bootstrap before shutting down their machine.
    Has anyone else seen this behavior? By the way, it works fine on Windows.

    Thanks in advance,
    Doug

  7. Devon May 30, 2008 at 10:50 am - Reply

    @Doug:

    my production system is Linux, so it isn’t a big deal for me. I have noticed that on my dev box (OS X Leopard), JBoss will create a JBoss Main process with a menu, which sounds similar. When I shutdown JBoss though, that process also dies. I haven’t looked into it much however.

    If you find out how to prevent it, I’d love to know.

    Thanks!

    Devon

  8. Doug May 30, 2008 at 11:27 am - Reply

    On the upside at least I am not alone. On the down side…no solution…yet…..

  9. Doug June 1, 2008 at 4:19 pm - Reply

    Hi Devon, I was wondering if you could perhaps help me on this problem. I have tried two different ways of sizing the image and have tracked it down to the following lines of code (from 2 different methods).

    First Way : ImageIcon imageIcon = new ImageIcon( pImageData ); //Where pImageData is the byte[]. When this line of code is executed the org.apache.catalina.startup.Bootstrap pops up on the upper right.

    Second way : Image image = Toolkit.getDefaultToolkit().createImage( pImageData );//Where pImageData is the byte[].
    When this line of code is executed the org.apache.catalina.startup.Bootstrap pops up on the upper right.

    Do you know of other ways of accomplishing this? The first example is right from this post. Any help would be GREATLY APPRECIATED!!!! I am at the point where I will try anything just to solve the problem.

    Thanks,
    Doug

  10. Devon June 1, 2008 at 4:30 pm - Reply

    @Doug:

    Try adding this to your start script:

    export JAVA_OPTS=”-Djava.awt.headless=true”

    Let me know if that helps.

  11. Doug June 1, 2008 at 5:21 pm - Reply

    It WORKS! You rock Devon!

    Thank you very much for your help I appreciate it.

  12. Devon June 1, 2008 at 5:22 pm - Reply

    @Doug:

    No problem! I’m glad it worked!

  13. Doug June 1, 2008 at 6:03 pm - Reply

    One last question please! What is the proper sytax for the following…it doesn’t seem to work when I want to put 2 parms on the JAVA_OPTS.
    I was setting just the memory and now I need the headless part as well. Can you tell me what is wrong with my JAVA_OPTS below?

    # JAVA_OPTS=”-Xms128M -Xmx512M”
    JAVA_OPTS=”-Djava.awt.headless=true;-Xms128M -Xmx512M”

    Thanks Again,
    Doug

  14. Devon June 1, 2008 at 6:05 pm - Reply

    @Doug:

    Just use spaces:

    JAVA_OPTS=”-Djava.awt.headless=true -Xms128M -Xmx512M”

  15. Doug June 1, 2008 at 6:14 pm - Reply

    Thanks!

  16. joaquin June 5, 2008 at 9:36 pm - Reply

    it works! i tried it and voila

    tks

  17. Marco August 25, 2008 at 11:54 am - Reply

    Thanks for this code. I’m a newbie in Java. Do you can share with us the final code and libraries initialization? I’m wanting to compile this and don’t know how to begin. Cheers.

  18. Devon August 25, 2008 at 12:57 pm - Reply

    @Marco:

    please look at this post:

    http://www.digitalsanctuary.com/tech-blog/java/how-to-resize-uploaded-images-using-java-better-way.html

    It generates better quality images by far.

    The imports for that code are:

    import java.awt.RenderingHints;
    import java.awt.image.renderable.ParameterBlock;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    
    import javax.media.jai.JAI;
    import javax.media.jai.OpImage;
    import javax.media.jai.RenderedOp;
    
    import com.sun.media.jai.codec.SeekableStream;
    
  19. Marco August 26, 2008 at 11:44 am - Reply

    Thanks Devon. I’ll try. One question: is possible to resize TIFF images using this code? What do you think about?

  20. Devon August 26, 2008 at 11:46 am - Reply

    @Marco: TIFF is a supported format so it should work just fine. Although i haven’t tested it myself.

  21. fui January 22, 2009 at 2:36 am - Reply

    int width = imageIcon.getIconWidth();
    int height = imageIcon.getIconHeight();

    both height and width return ‘-1’ for TIFF format.

    means TIFF not supported ?

  22. Devon January 22, 2009 at 2:22 pm - Reply

    @Fui: please try the code here: http://www.digitalsanctuary.com/tech-blog/java/how-to-resize-uploaded-images-using-java-better-way.html

    It’s better quality and may fix your issue as well.

  23. Danelle March 6, 2009 at 12:42 pm - Reply

    Thanks ! Worked great for me too.

  24. venu February 22, 2011 at 12:31 am - Reply

    Hi Devon.i am uploading 5 images using<rich:upload up to that every thing working fine.after saving that images. i want to display uploaded image as <rich:modelpanel pop up.i have no idea that how uploded image will come into modelpanel.please help me

    • Devon February 22, 2011 at 9:29 pm - Reply

      Venu,

      well I assume you’re able to serve up the images based on an id or name? Either from a Servlet pulling from your DB, or directly from the FS or wherever you put the images after upload. If you can do that, you just add the reference to the image in the modal panel.

      You define your modal:

      <rich:modalPanel id="pictureModal" autosized="true" width="750" zindex="2000">

      And add an image tag for the image:

      <img src="#{facesContext.externalContext.requestContextPath}/image/#{selectedImage.image.id}.jpg" />

      where selectedImage is your backing bean pointing to the image you want to display.

      If you want this to work without a page reload, you need to put the img src inside a ajax re-renderable block. If you’re using seam you can use s:div, otherwise an a4j tag should work

Leave A Comment Cancel reply