protected static void log(int depth, String message, Object... params) {
		if (Scalr.DEBUG) {
			System.out.print(Scalr.LOG_PREFIX);

			for (int i = 0; i < depth; i++)
				System.out.print("\t");

			System.out.printf(message, params);
			System.out.println();
		}
	}

	/**
	 * Used to create a {@link BufferedImage} with the most optimal RGB TYPE (
	 * {@link BufferedImage#TYPE_INT_RGB} or {@link BufferedImage#TYPE_INT_ARGB}
	 * ) capable of being rendered into from the given <code>src</code>. The
	 * width and height of both images will be identical.
	 * <p/>
	 * This does not perform a copy of the image data from <code>src</code> into
	 * the result image; see {@link #copyToOptimalImage(BufferedImage)} for
	 * that.
	 * <p/>
	 * We force all rendering results into one of these two types, avoiding the
	 * case where a source image is of an unsupported (or poorly supported)
	 * format by Java2D causing the rendering result to end up looking terrible
	 * (common with GIFs) or be totally corrupt (e.g. solid black image).
	 * <p/>
	 * Originally reported by Magnus Kvalheim from Movellas when scaling certain
	 * GIF and PNG images.
	 * 
	 * @param src
	 *            The source image that will be analyzed to determine the most
	 *            optimal image type it can be rendered into.
	 * 
	 * @return a new {@link BufferedImage} representing the most optimal target
	 *         image type that <code>src</code> can be rendered into.
	 * 
	 * @see <a
	 *      href="http://www.mail-archive.com/java2d-interest@capra.eng.sun.com/msg05621.html">How
	 *      Java2D handles poorly supported image types</a>
	 * @see <a
	 *      href="http://code.google.com/p/java-image-scaling/source/browse/trunk/src/main/java/com/mortennobel/imagescaling/MultiStepRescaleOp.java">Thanks
	 *      to Morten Nobel for implementation hint</a>
	 */
	protected static BufferedImage createOptimalImage(BufferedImage src) {
		return createOptimalImage(src, src.getWidth(), src.getHeight());
	}

	/**
	 * Used to create a {@link BufferedImage} with the given dimensions and the
	 * most optimal RGB TYPE ( {@link BufferedImage#TYPE_INT_RGB} or
	 * {@link BufferedImage#TYPE_INT_ARGB} ) capable of being rendered into from
	 * the given <code>src</code>.
	 * <p/>
	 * This does not perform a copy of the image data from <code>src</code> into
	 * the result image; see {@link #copyToOptimalImage(BufferedImage)} for
	 * that.
	 * <p/>
	 * We force all rendering results into one of these two types, avoiding the
	 * case where a source image is of an unsupported (or poorly supported)
	 * format by Java2D causing the rendering result to end up looking terrible
	 * (common with GIFs) or be totally corrupt (e.g. solid black image).
	 * <p/>
	 * Originally reported by Magnus Kvalheim from Movellas when scaling certain
	 * GIF and PNG images.
	 * 
	 * @param src
	 *            The source image that will be analyzed to determine the most
	 *            optimal image type it can be rendered into.
	 * @param width
	 *            The width of the newly created resulting image.
	 * @param height
	 *            The height of the newly created resulting image.
	 * 
	 * @return a new {@link BufferedImage} representing the most optimal target
	 *         image type that <code>src</code> can be rendered into.
	 * 
	 * @throws IllegalArgumentException
	 *             if <code>width</code> or <code>height</code> are &lt; 0.
	 * 
	 * @see <a
	 *      href="http://www.mail-archive.com/java2d-interest@capra.eng.sun.com/msg05621.html">How
	 *      Java2D handles poorly supported image types</a>
	 * @see <a
	 *      href="http://code.google.com/p/java-image-scaling/source/browse/trunk/src/main/java/com/mortennobel/imagescaling/MultiStepRescaleOp.java">Thanks
	 *      to Morten Nobel for implementation hint</a>
	 */
	protected static BufferedImage createOptimalImage(BufferedImage src,
			int width, int height) throws IllegalArgumentException {
		if (width <= 0 || height <= 0)
			throw new IllegalArgumentException("width [" + width
					+ "] and height [" + height + "] must be > 0");

		return new BufferedImage(
				width,
				height,
				(src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB
						: BufferedImage.TYPE_INT_ARGB));
	}

	/**
	 * Used to copy a {@link BufferedImage} from a non-optimal type into a new
	 * {@link BufferedImage} instance of an optimal type (RGB or ARGB). If
	 * <code>src</code> is already of an optimal type, then it is returned
	 * unmodified.
	 * <p/>
	 * This method is meant to be used by any calling code (imgscalr's or
	 * otherwise) to convert any inbound image from a poorly supported image
	 * type into the 2 most well-supported image types in Java2D (
	 * {@link BufferedImage#TYPE_INT_RGB} or {@link BufferedImage#TYPE_INT_ARGB}
	 * ) in order to ensure all subsequent graphics operations are performed as
	 * efficiently and correctly as possible.
	 * <p/>
	 * When using Java2D to work with image types that are not well supported,
	 * the results can be anything from exceptions bubbling up from the depths
	 * of Java2D to images being completely corrupted and just returned as solid
	 * black.
	 * 
	 * @param src
	 *            The image to copy (if necessary) into an optimally typed
	 *            {@link BufferedImage}.
	 * 
	 * @return a representation of the <code>src</code> image in an optimally
	 *         typed {@link BufferedImage}, otherwise <code>src</code> if it was
	 *         already of an optimal type.
	 * 
	 * @throws IllegalArgumentException
	 *             if <code>src</code> is <code>null</code>.
	 */
	protected static BufferedImage copyToOptimalImage(BufferedImage src)
			throws IllegalArgumentException {
		if (src == null)
			throw new IllegalArgumentException("src cannot be null");

		// Calculate the type depending on the presence of alpha.
		int type = (src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB
				: BufferedImage.TYPE_INT_ARGB);
		BufferedImage result = new BufferedImage(src.getWidth(),
				src.getHeight(), type);

		// Render the src image into our new optimal source.
		Graphics g = result.getGraphics();
		g.drawImage(src, 0, 0, null);
		g.dispose();

		return result;
	}

	/**
	 * Used to determine the scaling {@link Method} that is best suited for
	 * scaling the image to the targeted dimensions.
	 * <p/>
	 * This method is intended to be used to select a specific scaling
	 * {@link Method} when a {@link Method#AUTOMATIC} method is specified. This
	 * method utilizes the {@link Scalr#THRESHOLD_QUALITY_BALANCED} and
	 * {@link Scalr#THRESHOLD_BALANCED_SPEED} thresholds when selecting which
	 * method should be used by comparing the primary dimension (width or
	 * height) against the threshold and seeing where the image falls. The
	 * primary dimension is determined by looking at the orientation of the
	 * image: landscape or square images use their width and portrait-oriented
	 * images use their height.
	 * 
	 * @param targetWidth
	 *            The target width for the scaled image.
	 * @param targetHeight
	 *            The target height for the scaled image.
	 * @param ratio
	 *            A height/width ratio used to determine the orientation of the
	 *            image so the primary dimension (width or height) can be
	 *            selected to test if it is greater than or less than a
	 *            particular threshold.
	 * 
	 * @return the fastest {@link Method} suited for scaling the image to the
	 *         specified dimensions while maintaining a good-looking result.
	 */
	protected static Method determineScalingMethod(int targetWidth,
			int targetHeight, float ratio) {
		// Get the primary dimension based on the orientation of the image
		int length = (ratio <= 1 ? targetWidth : targetHeight);

		// Default to speed
		Method result = Method.SPEED;

		// Figure out which scalingMethod should be used
		if (length <= Scalr.THRESHOLD_QUALITY_BALANCED)
			result = Method.QUALITY;
		else if (length <= Scalr.THRESHOLD_BALANCED_SPEED)
			result = Method.BALANCED;

		if (DEBUG)
			log(2, "AUTOMATIC scaling method selected: %s", result.name());

		return result;
	}

	/**
	 * Used to implement a straight-forward image-scaling operation using Java
	 * 2D.
	 * <p/>
	 * This method uses the Oracle-encouraged method of
	 * <code>Graphics2D.drawImage(...)</code> to scale the given image with the
	 * given interpolation hint.
	 * 
	 * @param src
	 *            The image that will be scaled.
	 * @param targetWidth
	 *            The target width for the scaled image.
	 * @param targetHeight
	 *            The target height for the scaled image.
	 * @param interpolationHintValue
	 *            The {@link RenderingHints} interpolation value used to
	 *            indicate the method that {@link Graphics2D} should use when
	 *            scaling the image.
	 * 
	 * @return the result of scaling the original <code>src</code> to the given
	 *         dimensions using the given interpolation method.
	 */
	protected static BufferedImage scaleImage(BufferedImage src,
			int targetWidth, int targetHeight, Object interpolationHintValue) {
		// Setup the rendering resources to match the source image's
		BufferedImage result = createOptimalImage(src, targetWidth,
				targetHeight);
		Graphics2D resultGraphics = result.createGraphics();

		// Scale the image to the new buffer using the specified rendering hint.
		resultGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
				interpolationHintValue);
		resultGraphics.drawImage(src, 0, 0, targetWidth, targetHeight, null);

		// Just to be clean, explicitly dispose our temporary graphics object
		resultGraphics.dispose();

		// Return the scaled image to the caller.
		return result;
	}
protected static void log ( int depth , String message , Object ... params ) { if ( Scalr . DEBUG ) { System . out . print ( Scalr . LOG_PREFIX ) ; for ( int i = 0 ; i < depth ; i ++ ) System . out . print ( "\t" ) ; System . out . printf ( message , params ) ; System . out . println ( ) ; } } protected static BufferedImage createOptimalImage ( BufferedImage src ) { return createOptimalImage ( src , src . getWidth ( ) , src . getHeight ( ) ) ; } protected static BufferedImage createOptimalImage ( BufferedImage src , int width , int height ) throws IllegalArgumentException { if ( width <= 0 || height <= 0 ) throw new IllegalArgumentException ( "width [" + width + "] and height [" + height + "] must be > 0" ) ; return new BufferedImage ( width , height , ( src . getTransparency ( ) == Transparency . OPAQUE ? BufferedImage . TYPE_INT_RGB : BufferedImage . TYPE_INT_ARGB ) ) ; } protected static BufferedImage copyToOptimalImage ( BufferedImage src ) throws IllegalArgumentException { if ( src == null ) throw new IllegalArgumentException ( "src cannot be null" ) ; int type = ( src . getTransparency ( ) == Transparency . OPAQUE ? BufferedImage . TYPE_INT_RGB : BufferedImage . TYPE_INT_ARGB ) ; BufferedImage result = new BufferedImage ( src . getWidth ( ) , src . getHeight ( ) , type ) ; Graphics g = result . getGraphics ( ) ; g . drawImage ( src , 0 , 0 , null ) ; g . dispose ( ) ; return result ; } protected static Method determineScalingMethod ( int targetWidth , int targetHeight , float ratio ) { int length = ( ratio <= 1 ? targetWidth : targetHeight ) ; Method result = Method . SPEED ; if ( length <= Scalr . THRESHOLD_QUALITY_BALANCED ) result = Method . QUALITY ; else if ( length <= Scalr . THRESHOLD_BALANCED_SPEED ) result = Method . BALANCED ; if ( DEBUG ) log ( 2 , "AUTOMATIC scaling method selected: %s" , result . name ( ) ) ; return result ; } protected static BufferedImage scaleImage ( BufferedImage src , int targetWidth , int targetHeight , Object interpolationHintValue ) { BufferedImage result = createOptimalImage ( src , targetWidth , targetHeight ) ; Graphics2D resultGraphics = result . createGraphics ( ) ; resultGraphics . setRenderingHint ( RenderingHints . KEY_INTERPOLATION , interpolationHintValue ) ; resultGraphics . drawImage ( src , 0 , 0 , targetWidth , targetHeight , null ) ; resultGraphics . dispose ( ) ; return result ; }
Used to write out a useful and well-formatted log message by any piece of
code inside of the imgscalr library.
<p/>
If a message cannot be logged (logging is disabled) then this method
returns immediately.
<p/>
<strong>NOTE</strong>: Because Java will auto-box primitive arguments
into Objects when building out the <code>params</code> array, care should
be taken not to call this method with primitive values unless
{@link Scalr#DEBUG} is <code>true</code>; otherwise the VM will be
spending time performing unnecessary auto-boxing calculations.

@param depth
The indentation level of the log message.
@param message
The log message in <a href=
"http://download.oracle.com/javase/6/docs/api/java/util/Formatter.html#syntax"
>format string syntax</a> that will be logged.
@param params
The parameters that will be swapped into all the place holders
in the original messages before being logged.

@see Scalr#LOG_PREFIX
@see Scalr#LOG_PREFIX_PROPERTY_NAME