Ok, so it’s not really in ColdFusion, but I wrong a Java library so that I could access image manipulation routines in my ColdFusion apps. Using the Java Advanced Imaging (JAI) API made it very easy to write a library to perform a variety of functions.

Requirements

The Java 1.5 JDK must be installed on your system and used to compile this code (or to use the library I provide). By default ColdFusion 6 and 7 support up to 1.4 JDK, so this is an unsupported bit of code.

Install the JAI Build

You can visit the Java Advanced Imaging Project page to download the binary for your OS of choice. By default the installation will place the files in your existing JDK or JRE location (for example, on Windows it will be something similar to C:\Program Files\Java\jre1.5.0_05), but you can override this and have the files installed directly into the LIB directory of your application server – for example – C:\jboss-4.0.4\server\default\lib.

Write a Java imaging class

Now we can start using those libraries to build a Java class, which you can use in ColdFusion. This is my simple class which you can use as a reference. I put in my notes and added links to the JAI specs page for specific operations.

package orbwave.ImageController;

/*
 * Import the JAI libraries and the IO libraries to read, manipulate and save
 * an image file.
 */
import java.io.*;
import java.awt.image.renderable.*;
import javax.media.jai.*;
import com.sun.media.jai.codec.*;

public class Controller {

	// Private member variable to hold the original iamge file
	private RenderedOp sourceFile = null;

	/*
	 * Load a source image into a FileSeekableStream object for manipulation
	 */
	public void load(String file) throws IOException
	{
	  FileSeekableStream fss = new FileSeekableStream(file);
	  sourceFile = JAI.create("stream", fss);
	}

	/*
	 * Save the manipulated image to the specified file location, with the
	 * specified type.  Set the sourceFile reference back to null to prevent
	 * the file from being locked by this process
	 */
	public void save(String file, String type) throws IOException
	{
	  FileOutputStream os = new FileOutputStream(file);
	  JAI.create("encode", sourceFile, os, type, null);
	  sourceFile = null;
	  os = null;
	}

	/*
	 * For cropping, I provide a simple 'centering' crop where the starting edges
	 * and the max edges are all equal
	 *
	 * Documentation:
	 * http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/CropDescriptor.html
	 */
	public void crop(float edge)
	{
	  ParameterBlock params = new ParameterBlock();
	  params.addSource(sourceFile);
	  params.add(edge);
	  params.add(edge);
	  params.add((float) sourceFile.getWidth() - edge);
	  params.add((float) sourceFile.getHeight() - edge);
	  sourceFile = JAI.create("crop", params);
	}

	/*
	 * This scale method does an incremental process of scaling until the desired width
	 * is achieved.  This process provides a MUCH smoother final image than a direct scale from
	 * the original size.
	 *
	 * Documenation:
	 * http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/ScaleDescriptor.html
	 */
	public void scaleWidth(float width)
	{
		ParameterBlock params;
		while (width < sourceFile.getWidth()) {
			float esc = Math.max(((float) (width) / sourceFile.getWidth()),0.5f);
			params = new ParameterBlock();
			params.addSource(sourceFile);
			params.add(esc).add(esc).add(0.0F).add(0.0F);
			params.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
			sourceFile = JAI.create("scale", params);
		}
	}

	/*
	 * This scale method does an incremental process of scaling until the desired height
	 * is achieved.  This process provides a MUCH smoother final image than a direct scale from
	 * the original size.
	 *
	 * Documenation:
	 * http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/ScaleDescriptor.html
	 */
	public void scaleHeight(float height)
	{
		ParameterBlock params;
		while (height < sourceFile.getHeight()) {
			float esc = Math.max(((float) (height) / sourceFile.getHeight()),0.5f);
			params = new ParameterBlock();
			params.addSource(sourceFile);
			params.add(esc).add(esc).add(0.0F).add(0.0F);
			params.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
			sourceFile = JAI.create("scale", params);
		}
	}

	/*
	 * This operation rotates an image about a given point by a given angle, specified
	 * in degrees. The origin defaults to (0, 0).
	 *
	 * Documentation:
	 * http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/RotateDescriptor.html
	 */
	public void rotate(float degrees)
	{
	  ParameterBlock params = new ParameterBlock();
	  params.addSource(sourceFile);
	  params.add((float)sourceFile.getWidth() / 2);
	  params.add((float)sourceFile.getHeight() / 2);
	  params.add(degrees);
	  params.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2));//interpolation method
	  sourceFile = JAI.create("rotate", params);
	}

	/*
	 * To create a thumbnail, I simply accept the maximum edge length wanted for the entire image
	 * and then compare with the width and height to determine which aspect should be used for
	 * resizing.
	 *
	 * Documenation:
	 * Refer to scaleHeight() or scaleWidth() methods for scale documentation
	 */
	public void createThumbnail(float edgeLength)
	{
	  boolean useHeight = (sourceFile.getHeight() > sourceFile.getWidth());
	  while ( edgeLength < ((useHeight) ? sourceFile.getHeight() : sourceFile.getWidth()) ) {
		  float esc = Math.max(((float) (edgeLength) / ((useHeight) ? sourceFile.getHeight() : sourceFile.getWidth()) ),0.5f);
		  ParameterBlock params = new ParameterBlock();
		  params.addSource(sourceFile);
		  params.add(esc);
		  params.add(esc);
		  params.add(0.0F);
		  params.add(0.0F);
		  params.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2));//interpolation method
		  sourceFile = JAI.create("scale", params);
	  }
	}
}

You can download the compiled library and place it in your WEB-INF\lib directory for your application.

orbwave.jar location

Control images via ColdFusion

After you’ve compiled your library, or downloaded my sample, you should restart your application server. Once it has restarted, you can start using the manipulation code in ColdFusion. Here’s some sample code.


<cfscript>
// Create an instance of the image editor
img = createobject("java", "orbwave.ImageController.Controller");

// Load a source file, scale to width to 320 pixels and save it
img.load('C:\\jboss-4.0.4\\server\\default\\deploy\\brownlees.war\\img\\DSC00121.JPG');
img.scalewidth(320);
img.save('C:\\jboss-4.0.4\\server\\default\\deploy\\brownlees.war\\img\\DSC00121_scaled.JPG','jpeg');

// Load a source file, scale to height to 320 pixels, rotate by 90 degrees and save it
img.load('C:\\jboss-4.0.4\\server\\default\\deploy\\brownlees.war\\img\\DSC00121.JPG');
img.scaleheight(320);
img.rotate(45);
img.save('C:\\jboss-4.0.4\\server\\default\\deploy\\brownlees.war\\img\\DSC00121_sclaed_rotated.JPG','jpeg');
</cfscript>