content: package tim.prune.gui;
  
  import java.awt.Dimension;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.Image;
  import java.awt.image.BufferedImage;
  import java.awt.image.ConvolveOp;
  import java.awt.image.Kernel;
  
  import javax.swing.ImageIcon;
  
  /**
   * Class for providing generic image processing functions
   */
  public abstract class ImageUtils
  {
  	private static final float SMOOTH_FACTOR = 0.008f;
  	private static ConvolveOp CONVOLVER = null;
  
  	/** Static block for initialization */
  	static
  	{
  		float[] smoothMatrix = {
  			0, SMOOTH_FACTOR, 0,
  			SMOOTH_FACTOR, 1-(SMOOTH_FACTOR*4), SMOOTH_FACTOR,
  			0, SMOOTH_FACTOR, 0
  		};
  		CONVOLVER = new ConvolveOp(new Kernel(3, 3, smoothMatrix));
  	}
  
  
  	/**
  	 * Create a scaled and smoothed image according to the specified size
  	 * @param inImage image to scale
  	 * @param inWidth width to scale to
  	 * @param inHeight height to scale to
  	 * @return BufferedImage containing scaled result
  	 */
  	public static BufferedImage createScaledImage(Image inImage, int inWidth, int inHeight)
  	{
  		if (inWidth <= 0 || inHeight <= 0) {
  			return null;
  		}
  		// create smaller image and force its loading
  		Image smallerImage = inImage.getScaledInstance(inWidth, inHeight, Image.SCALE_SMOOTH);
  		Image tempImage = new ImageIcon(smallerImage).getImage();
  		tempImage.getWidth(null);
  
  		// create buffered image to do transform
  		BufferedImage buffer = new BufferedImage(inWidth, inHeight, BufferedImage.TYPE_INT_RGB);
  		// copy scaled picture into buffer
  		Graphics buffG = buffer.getGraphics();
  		buffG.drawImage(smallerImage, 0, 0, inWidth, inHeight, null);
  		buffG.dispose();
  
  		// smooth scaled image using a normalized 3x3 matrix - taking next neighbour
  		buffer = CONVOLVER.filter(buffer, null);
  
  		return buffer;
  	}
  
  
  	/**
  	 * Work out the max size of a thumbnail
  	 * @param inOrigWidth width of original picture
  	 * @param inOrigHeight height of original picture
  	 * @param inMaxWidth max width of thumbnail
  	 * @param inMaxHeight max height of thumbnail
  	 * @return size of thumbnail as Dimension
  	 */
  	public static Dimension getThumbnailSize(int inOrigWidth, int inOrigHeight, int inMaxWidth, int inMaxHeight)
  	{
  		if (inMaxWidth <= 0 || inMaxHeight <= 0) {return new Dimension(1, 1);}
  		// work out maximum zoom ratio available so that thumbnail isn't too big
  		double xZoom = inMaxWidth * 1.0 / inOrigWidth;
  		double yZoom = inMaxHeight * 1.0 / inOrigHeight;
  		final double zoom = Math.min(xZoom, yZoom);
  		// Don't make thumbnail bigger than picture
  		if (zoom > 1.0) {return new Dimension(inOrigWidth, inOrigHeight);}
  
  		// calculate new width and height
  		final int xSize = (int) (zoom * inOrigWidth);
  		final int ySize = (int) (zoom * inOrigHeight);
  		if (xSize <= 0 || ySize <= 0) {return new Dimension(1, 1);}
  		return new Dimension (xSize, ySize);
  	}
  
  
  	/**
  	 * Create a new image by rotating and scaling the given one
  	 * @param inImage input image
  	 * @param inMaxWidth maximum width of output image
  	 * @param inMaxHeight maximum height of output image
  	 * @param inRotationDegrees number of degrees to rotate clockwise (0, 90, 180 or 270)
  	 * @return rotated, scaled image
  	 */
  	public static BufferedImage rotateImage(Image inImage, int inMaxWidth, int inMaxHeight, int inRotationDegrees)
  	{
  		// Create scaled image of suitable size
  		boolean isRotated = (inRotationDegrees % 180 != 0);
  		int origWidth = inImage.getWidth(null);
  		int origHeight = inImage.getHeight(null);
  		int thumbWidth = isRotated?origHeight:origWidth;
  		int thumbHeight = isRotated?origWidth:origHeight;
  		Dimension scaledSize = getThumbnailSize(thumbWidth, thumbHeight, inMaxWidth, inMaxHeight);
  		BufferedImage result = new BufferedImage(scaledSize.width, scaledSize.height, BufferedImage.TYPE_INT_RGB);
  		// Do different things according to rotation angle (a bit messy, sorry!)
  		if (inRotationDegrees == 0)
  		{
  			// Not rotated, so just copy image directly
  			result.getGraphics().drawImage(inImage, 0, 0, scaledSize.width, scaledSize.height, null);
  		}
  		else
  		{
  			// Need to use Graphics2D for rotation, not Graphics
  			Graphics2D g2d = result.createGraphics();
  			switch (inRotationDegrees)
  			{
  				case 90:
  					g2d.rotate(Math.PI / 2, 0.0, 0.0);
  					g2d.drawImage(inImage, 0, -scaledSize.width, scaledSize.height, scaledSize.width, null);
  					break;
  				case 180:
  					g2d.rotate(Math.PI, scaledSize.width/2.0, scaledSize.height/2.0);
  					g2d.drawImage(inImage, 0, 0, scaledSize.width, scaledSize.height, null);
  					break;
  				case 270:
  					g2d.rotate(Math.PI * 3/2, 0.0, 0.0);
  					g2d.drawImage(inImage, -scaledSize.height, 0, scaledSize.height, scaledSize.width, null);
  			}
  			// Clear up memory
  			g2d.dispose();
  		}
  		return result;
  	}
  }
  