Image Cropping with ColdFusion & jQuery

ColdFusion 8 was an amazing release. The addition of the many image-related functions and cfImage tags certainly enhanced an already fantastic server-side language. They are fun to use, fun to write, and incredibly simple.

I wanted to have a quick play around with some front-end code to create a user-interface to dynamically crop an image using ColdFusion. Todd Sharp, Mr. himself, developed a fantastic ColdFusion custom tag called cfImageCropper a few years ago to handle image cropping within CF. I’ve used this custom tag a few times in the past on various projects. If you haven’t seen it or given it a test run, make sure you do.

Instead of creating a custom tag, my small demonstration example uses jQuery and in particular a supersweet plugin called Jcrop to handle the core of the user-experince code and creating the crop marker. Here’s a short video of the code in action (it will open in a new window):

View the video at


The HTML for the page and demonstration is fairly simple. The page contains a form which holds the required image-related values (X and Y positions, width and height, and the original image file name) which will be sent to the crop.cfm page to perform the image manipulation.

A thumbnail menu on the right hand side of the page contains the images available to load into the main view, from which you can perform the cropping.

	<title>coldfumonkeh : Jcrop and ColdFusion - image cropping</title>
	<script src="js/jquery.min.js"></script>
	<script src="js/jquery.Jcrop.js"></script>
	<link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
	<link rel="stylesheet" href="css/style.css" type="text/css" />

	<!-- our script will go here -->
    <script language="Javascript">


	<div id="outer">
	<div class="imageContainer">
	<h2>jCrop and ColdFusion</h2>	
		<!-- The event handler from the JCrop plugin populates these
			values for us. Required to obtain the X Y coords and persist
			the image location for cropping and reverting the image. -->
		<form action="crop.cfm" method="post">
			<input type="hidden" size="4" id="x" name="x" />
			<input type="hidden" size="4" id="y" name="y" />
			<input type="hidden" size="4" id="x2" name="x2" />
			<input type="hidden" size="4" id="y2" name="y2" />
			<input type="hidden" size="4" id="w" name="w" />
			<input type="hidden" size="4" id="h" name="h" />
			<input type="hidden" name="imageFile" 
					id="imageFile" value="" />		
			<input type="button" name="imageCrop_btn" 
					id="imageCrop_btn" value="Crop the image" />
			<input type="button" name="revert_btn" 
					id="revert_btn" value="Revert to original" />
		<!-- This is the image we're attaching Jcrop to -->
		<div id="croppedImage">
            <img src="images/ZamakRobots1.jpg" id="cropbox" />
		<div id="thumbs">
			<ul class="thumb">

				<li><a href="images/ZamakRobots1.jpg">
				<img src="images/thumbs/ZamakRobots1.jpg" alt="Image 1" />

				<li><a href="images/ZamakRobots2.jpg">
				<img src="images/thumbs/ZamakRobots2.jpg" alt="Image 2" />

				<li><a href="images/ZamakRobots3.jpg">
				<img src="images/thumbs/ZamakRobots3.jpg" alt="Image 3" />

		<p>This demonstration uses the awesome 
		<a href="" title="Jcrop jQuery plugin" 
			target="_blank">Jcrop jQuery plugin</a> from Deep Liquid.</p>
		<p>Robots designed by <a href="" 
			title="Oliver Bucheron at" target="_blank">
			Olivier Bucheron</a>.</p>
        <p>Thumbnail hover effect inspired by 
            <a href="" 
            title="" target="_blank"></a>.</p>

One item to note here is the DIV element containing the main image, and more importantly the id attribute of the image within:


The Jcrop plugin needs to be invoked and applied to a particular element on the page to which it adds the crop functionality. It is this id attribute (‘cropbox‘) that is used as that reference for the plugin. Without this, the Jcrop plugin will not be able to apply the crop marker to the image.

The script

Thanks to the awesome-ness of the open-source community and the wealth of plugins now available for use with the jQuery library, the core funtionality for the animation, placement and positioning of the cropping tool / marker is all handled by the Jcrop plugin. With a few lines of code to invoke the plugin and specify some default options, you can have the tool up and running in seconds.

Being the adventurous guy that I am, I obviously went a little further and added some extra variables and functions into the script body (leaving the plugin intact).

The plugin allows you to specify a specific position on the image to place the crop marker tool upon invocation, using the ‘setSelect‘ parameter.
I wanted to obtain the image dimensions and work out the required X and Y positions for the marker, including an area of padding to provide some kind of visual border and to control the initial crop-position.


To do this, a static variable for ‘padding’ was set to 10px, and the X and Y coordinates were calculated by subtracting the padding value from the originalImgHeight and originalImgWidth variables respectively.

The main bulk of the javascript code is below.

jQuery(document).ready(function() {			

// obtain original image dimensions
var originalImgHeight 	= jQuery('#cropbox').height();
var originalImgWidth 	= jQuery('#cropbox').width();

// set the padding for the crop-selection box
var padding = 10;
// set the x and y coords using the image dimensions
// and the padding to leave a border
var setX = originalImgHeight-padding;
var setY = originalImgWidth-padding;
// create variables for the form field elements
var imgX 		= jQuery('input[name=x]');
var imgY 		= jQuery('input[name=y]');
var imgHeight 	= jQuery('input[name=h]');
var imgWidth 	= jQuery('input[name=w]');
var imgLoc 	    = jQuery('input[name=imageFile]');
// get the current image source from the main view
var currentImage = jQuery("#croppedImage img").attr('src');

// set the imageFile form field value to match
// the new image source
function setImageFileValue(imageSource) {

// instantiate the jcrop plugin

// add the jQuery invocation into a separate function,
// which we will need to call more than once
function buildJCrop() {
        // set to zero to allow for non-constrained cropping
        aspectRatio: 0,
        // set the event handler function
        onChange: showCoords,
        onSelect: showCoords,
        // this param will add the crop area to the specified
        // point on the image on startup.
        setSelect: [padding,padding,setY,setX]
    // enable the image crop button and
    // disable the revert button for usability.
    // After invocation, we only want to allow the user the ability
    // to crop the image.
    jQuery('#revert_btn').attr('disabled', 'disabled');

// extra functions to go here

// end of jQuery(document).ready

// Our simple event handler, called from onChange and onSelect
// event handlers, as per the Jcrop invocation above.
// This function sets the values of the hidden form fields with 
// the X Y coords and the dimensions of the crop mark area.
function showCoords(c) {

Ah, click it. Click it real good.

The following two functions are added within the main jQuery(document).ready method after the existing code, and both handle the onclick events for the two action buttons within the form – ‘revert_btn‘ and ‘imageCrop_btn‘.

The crop button generates a string variable (‘data‘) that concatenates the values from the hidden form fields containing the image crop marker information and generates the URL query string to send to the crop.cfm page, passing it into the jQuery.load() function. After the click, we disable the button and enable the image revert button to allow the user to restore the original file into view.

    // organise data into a readable string
    var data = 'imgX=' + imgX.val() + '&imgY=' + imgY.val() + 
        '&height=' + imgHeight.val() + '&width=' + imgWidth.val() + 
        '&imgLoc=' + encodeURIComponent(imgLoc.val());
    // disable the image crop button and
    // enable the revert button
    jQuery('#imageCrop_btn').attr('disabled', 'disabled');
    // do not submit the form using the default behaviour
    return false;

The revert button generates the HTML img tag, complete with the ‘id=”cropbox”‘ attribute. The Jcrop invocation uses this element ID to place the crop marker functionality onto the image. We obtain the src attribute of the image from the hidden imageFile form field using the name class selector.

// extra functions to go here 

// selecting revert will create the img html tag complete with
// image source attribute, read from the imageFile form field
jQuery("#revert_btn").click(function() {					
    var htmlImg = '<img src="' + jQuery('input[name=imageFile]').val() 
        + '" id="cropbox" />';
    // instantiate the jcrop plugin

As a reminder, within the buildJCrop function that invokes the plugin into existence and applies it to the active ‘#cropbox‘ element, we also set the default ‘enabled’ values for the two action buttons:

// enable the imageCrop_btn
// disable the revert_btn
jQuery('#revert_btn').attr('disabled', 'disabled');

This is to ensure that only the ‘image crop’ button is active and enabled when the image is ready to be cropped. There’s no point having an active revert button if there’s nothing to revert. :)

Enlarged thumbnail image

To add some extra functionality to the user experience, the thumbnail menu has some very clever (but relatively simple) jQuery code applied to create a unique hover effect to each thumbnail item.

enlarged thumbnail

This controls the z-index property of each image, and enlarges the thumbnail and alters the stack order when hovering over the image, which can be seen in the code below.

jQuery("ul.thumb li").hover(function() {
    // increase the z-index to ensure element stays on top
    jQuery(this).css({'z-index' : '10'});
    // add hover class and stop animation queue
            // vertically align the image
            marginTop: '-110px', 
            marginLeft: '-110px',
            top: '50%',
            left: '50%',
            // set width
            width: '174px',
            // set height
            height: '174px',
            padding: '20px'
        // set hover animation speed
    } , function() {
        // set z-index back to zero
        jQuery(this).css({'z-index' : '0'});
        // remove the hover class and stop animation queue
                // reset alignment to default
                marginTop: '0',
                marginLeft: '0',
                top: '0',
                left: '0',
                // reset width
                width: '100px',
                // reset height
                height: '100px',
                padding: '5px'
            }, 400);

        // onclick action for the thumbnails
        jQuery("ul.thumb li a").click(function() {
        // check to see if  id="cropbox" attribute exists
        // in the img html
        if (!jQuery("#croppedImage img").attr('id')) {
            // no attribute exists. add it in
            jQuery("#croppedImage img").attr('id', 'cropbox')
        // instantiate the jcrop plugin
        // Get the image name
        var mainImage = $(this).attr("href");
        jQuery("#croppedImage img").attr({ src: mainImage });
        return false;		

Loading the thumbnail image

Each menu list item has an onclick function applied to the ‘a‘ element which essentially finds the href attribute containing the path to the full-size version of the image, and adds that value to the src attribute of the img tag within the main view.

One thing to note here.. whenthe crop.cfm remote image is loaded in (using the writeToBrowser functionality offered by the cfimage tag) there is no id attribute applied to the HTML. The response from the dynamically generated image is similar to this:

If the user selects an item from the menu to load after cropping an existing image and before clicking the revert button, the id attribute needs to be set to ‘cropbox‘, as we want to apply the Jcrop functionality to the newly loaded image. To do this, we have this small block of code within the above script block that checks for the existence of the id attribute in the img tag.

// check to see if  id="cropbox" attribute exists  
// in the img html  
if (!jQuery("#croppedImage img").attr('id')) {  
// no attribute exists. add it in  
    jQuery("#croppedImage img").attr('id', 'cropbox')  

If it doesnt exist, it will be added with the required value before the img src attribute is updated with that of the new image.

Handling the crop

Lastly, but by no means least, the ColdFusion page that handles the cropping of the image. Incredibly simple in terms of code and function, the crop.cfm page simply uses the variables passed through to it via the URL scope from the calling page (the form variables sent via the jQuery.load() method).

The original image is read using the source attribute supplied in the query string, and a ColdFusion image object is created. It is then cropped to size using the ImageCrop() function, and the resulting cropped image then written out to the browser.

<cfsetting showdebugoutput="false">
<!--- hide debugoutput. You dont want to 
	        return the debug information as well --->

<!--- set the params for the image dimensions --->
<cfparam name="url.imgX" 	type="numeric" 	default="0" />
<cfparam name="url.imgY" 	type="numeric" 	default="0" />
<cfparam name="url.width" 	type="numeric" 	default="0" />
<cfparam name="url.height" 	type="numeric" 	default="0" />
<cfparam name="url.imgLoc" 	type="string" 	default="" />

<cfif len(url.imgLoc)>

    <!--- read the image and create a ColdFusion image object --->
    <cfimage source="#url.imgLoc#" name="sourceImage" />

    <!--- crop the image using the supplied coords 
              from the url request --->
    <cfset ImageCrop(sourceImage, 
                        url.height) />

    <!--- write the revised/cropped image to the browser
                    to display on the calling page --->
    <cfimage source="#sourceImage#" 
                action="writeToBrowser" />


With the exception of creating the cfparam tags and the cfif block, the main code here that is actually required to crop and generate an image on the fly is three lines of code (a little more if you space them as I have done for readability, but, you know…).

I ran a test a few years ago when ColdFusion 8 was first released. Given that ColdFusion can create a CAPTCHA image in one line of code, I wanted to see how it compared writing the same CAPTCHA image in PHP. Needless to say, my code block had gone well over the one line CF needed to get the same job done.

True, there is a heck of a lot of core work going on under the hood that actually produces the results we want from the simple tags we supply, and that is a testament to Allaire, Macromedia and Adobe for creating and evolving a superb server-side language that is incredibly powerful and easy to use, but the fact still remains.. you can do more in ColdFusion in less time.

And that HAS to be a good thing, right? Right?! Yeah it is.

Fin (the end)

That’s about it really. Working on this small demo project has been great fun. I must admit it’s been a few months since I’ve got my hands dirty with jQuery, but getting back into it was great fun. Obviously one major factor to take away from this example is the fact that ColdFusion makes cropping images incredibly easy – as it does with basically everything else you can throw at it. :)

The source code is available here, so please feel free to download and have a play around with it yourselves.

  • Pingback: Creating logos and images in ColdFusion | Matt Gifford AKA ColdFuMonkeh

  • Ben Nadel

    This looks really slick. I especially love the increasing of the thumbnails when you roll over them.

  • Matt

    Thanks Ben! I had awesome fun working on this.

  • Dan

    Awesome! I love it. How would I be able to take the cropped image and save it to the folder? Using cffile?

  • Ryan LeTulle

    Thanks so much for the thorough example. It’s really nice.

  • Brad Goettemoeller

    Wow. This is really great. Thanks for sharing.

    I’ve just downloaded the source code and getting familiar with it. I’m trying to customize what you’ve done here so that I can easily manipulate photos to fit a new website format. I need the selection box to be a specific width and height. I see that there is an aspect ratio variable but is there a way to fix the size of the box to be a specific size and not change?

    I will make sure the original photo is at least that size before we get to the cropping part.

  • Brad Goettemoeller

    I just figured it out. Those variables are specified in js/jquery.Jcrop.js.

  • Matt

    Hey Brad!

    Morning has only just broken here in the UK, so have only just seen your comments, but I’m glad you found the location in the js file to set the ratio variables.

    Have fun!


  • Tom K

    Hi Matt; great stuff!
    Now I’ve just got to work out how to pass the src attribute of the returned image to another form to save.. :)

  • Wendy

    Do you know if it would be possible to do multiple preview boxes on one page?

    Say, for example, I have a big main image (600×400) , then I want to create 5 other images as scaled crops of the main image, e.g. a 100×100, 440×135, 140×91 to use in different areas of the website.
    Ideally, I want to be able to preview and change all of the crops on the same page, then save them all at once.

  • Matt

    @Wendy – do you mean you’d like to alter each cropped version of the main image independently, so each one has a separate crop tool placement?

  • Matt

    @Tom K – were you able to get the src attribute passed to the form? I’m sorry i hadn’t replied earlier; I literally just saw this comment :| It can be done quite easily, so if you need to, we can go over it in another post (or if anyone else is interested)

  • Marco

    How would one pass additional variables into crop.cfm? Thanks.

  • Matt

    @Marco –

    the data variable within the button .click function creates a concatenated string of any/all variables we need to send to the crop.cfm page:

    // organise data into a readable string
    var data = ‘imgX=’ + imgX.val() + ‘&imgY=’ + imgY.val() +
    ‘&height=’ + imgHeight.val() + ‘&width=’ + imgWidth.val() +
    ‘&imgLoc=’ + encodeURIComponent(imgLoc.val());
    // disable the image crop button and
    // enable the revert button
    jQuery(‘#imageCrop_btn’).attr(‘disabled’, ‘disabled’);
    // do not submit the form using the default behaviour
    return false;

    Depending on what you need to send through, you need to edit this function to append any extra values onto the data variable to create the revised URL string.

    Have a look at the jQuery.load() method for more details:

    Is there something specific you are looking to send through?

  • Wendy

    Hi Matt! Yes that was exactly what I’m trying to achieve… think I’m getting there now though.. have saved all the coordinates of the 5 different preview images into hidden form fields by looping through the x, y , x2, y2 vals… so am just working on saving off all of the new images… am using the Jcrop previews which crop and scale at once instead of just cropping..

    • Matt

      @Wendy – Awesome! it sounds like you’ve got it sorted :) Would love to see the finished result if you’d be happy to share code/url when you’re done?

  • Wendy

    Hi Matt
    So here’s an example for saving multiple crop sizes at once … these are just some snippets as to how it can be achieved….

    In the javascript, set up an array of 6 crop coordinates e.g. :
    var ac = {
    anim1: [ 2,97,609,284 ],
    anim2: [ 0,96,610,287 ],
    anim3: [ 0,0, 610,396 ],
    anim4: [ 102,0,498,396 ],
    anim5: [ 0,68,610,340 ],
    anim6: [ 0,36,610,367 ]

    Add a function to update the hidden form fields on click, e.g.

    function updateForm(coords){
    var cropbox = $(“##cropbox”),
    index = $(“.preview-boxes img”).index($(“.preview”)),
    currInputX1 = $(“.preview-boxes div”).eq(index).find(“input.posX1″);
    currInputY1 = $(“.preview-boxes div”).eq(index).find(“input.posY1″);
    currInputX2 = $(“.preview-boxes div”).eq(index).find(“input.posX2″);
    currInputY2 = $(“.preview-boxes div”).eq(index).find(“input.posY2″);
    currInputH = $(“.preview-boxes div”).eq(index).find(“input.posH”);
    currInputW = $(“.preview-boxes div”).eq(index).find(“input.posW”);

    // update inputs

    // update preview thumbnails

    Then call this function in the onChange, and onSelect e.g. :
    jcrop_api = $.Jcrop(‘##cropbox’,{
    onChange: updateForm,
    onSelect: updateForm

    For the form, add the hidden form fields and preview boxes: e.g. (the div class is important here)

    To attach the event handlers that will pick up the default crop areas, add something like this .. (the determineAspectRatio function could be used to get the aspect ratio for each image by dividing the width by height) :

    for(i in ac) {
    $(“.preview-boxes img”).removeClass(“preview”);
    jcrop_api.setOptions({aspectRatio: determineAspectRatio(});

    • Matt

      Hey Wendy!

      Wow, thanks for posting this up and sharing the code :) It looks great. The comment form seems to have stripped out all HTML tags. Any chance you could email me the code example you provided above (perhaps in an html doc or with escaped characters) or you can post the comment again with all characters escaped?

      Awesome work, and looking forward to seeing the full code if possible :)

  • David Sedeño


    I have this in production and some users complain about this error:

    Invalid parameter type. The value cannot be converted to a numeric because it is not a simple value.Simple values are booleans, numbers, strings, and date-time values. The error occurred on line 21.

    The line is:

    I can not reproduce it so it’s hard to debug.
    Do you have any idea about this error?

    Thanks in advances

    • Matt

      Hi David

      the line error details were stripped out of the comment after submitting. Can you send me the details using the comment form on my contact page? Or email me @ mattgifford dot co dot uk

  • Sascha

    hello matt

    great script, thanx for your great work!

    i just have one question: is there a way to define a square as crop area?


    • Matt

      Hi Sascha

      do you men constraining proportions of the crop area? That can be done by changing the value aspectRatio = 1 in the script.

  • Marco

    Any thoughts on how to get this to work on iPhone/iPad/iOS5?

    The problem comes in being able to drag the edges of the crop markers.


  • Carlo

    Hy Matt, Thank you for your works it was really helpfully for me.
    I have another method to use jCrop v0.9.10 and ColdFusion 9 , it support image cropping
    and resizing at the same moment. I would like to share my code, may be will be helpfully for others.
    Example for crop an image to 980×240

    — index.cfm —


    var alreadysubmitted = false;
    function controlform()
    if(alreadysubmitted == false)
    alreadysubmitted = true;
    alert(‘Wait please.’);
    return false;

    function salta()
    return false;


    // Create variables (in this scope) to hold the API and image size
    var imgX = jQuery(‘input[name=boundx]‘);
    var imgY = jQuery(‘input[name=boundy]‘);
    var imgHeight = jQuery(‘input[name=h]‘);
    var imgWidth = jQuery(‘input[name=w]‘);

    var jcrop_api, boundx, boundy;

    onChange: updatePreview,
    onSelect: updatePreview,
    aspectRatio: 940/240,
    onSelect: updateCoords
    // Use the API to get the real image size
    var bounds = this.getBounds();
    boundx = bounds[0];
    boundy = bounds[1];
    // Store the API in the jcrop_api variable
    jcrop_api = this;

    function updatePreview(c)
    if (parseInt(c.w) > 0)
    var rx = 980 / c.w;
    var ry = 240 / c.h;

    width: Math.round(rx * boundx) + ‘px’,
    height: Math.round(ry * boundy) + ‘px’,
    marginLeft: ‘-‘ + Math.round(rx * c.x) + ‘px’,
    marginTop: ‘-‘ + Math.round(ry * c.y) + ‘px’


    function updateCoords(c)

    function checkCoords()
    if (parseInt($(‘#w’).val())) return true;
    alert(‘Please select a crop region then press submit.’);
    return false;



    —– crop.cfm—–


    that’s all

    • Matt

      Hi Carlo

      Thanks for your comment. Unfortunately the filter strippe out all of the tags. Could you resend the comment, replacing all opening and closing tag brackets with < and > ?

      Many thanks,


  • Joseph Esquivel

    Thank you for providing such a great resource! I was able to get this to work all except saving the cropped image. I am needing to FTP the cropped image to a different server and directory. How might I grab the cropped file and ftp? I am more confused on the source of the cropped image, not so much the ftp. Yes, pretty vague in my question but I am not even sure if I am asking the right thing, to be honest. Thanks for any advice.

  • Jan

    Hi there,

    Great tutorial and support here!

    I have almost got it working but in a Bootstrap environment it is doing really weird things! I downloaded the latest version of the plugin that people on the JCrop website said would work, but it doesn’t!

    I need the image to be bound to a specific size: 1000pixels x 329 pixels – this is fine when the image loads the bounding box is there, but as soon as I move the box it disappears and then only manages to show up when you click furiously on the image. Any ideas??

    I can show you it live but I will need to send you the URL via PM.



  • Jeremy Cole

    Could the functionality be added to upload and preview the image in the cropper?

    • Jeremy Cole

      Nvm I figured it out :D