jQuery Thickbox and ColdFusion Dynamic Image Resizing

This post is more than 2 years old.

Ok, is it just me, or has JavaScript spoiled me? It seems like almost daily I come across a web page with a long list of image thumbnails. I click on one and the entire page reloads. I click back and get a whole other large page load. I click on another image, and, well, you get the idea. I hate this. I've blogged before about the jQuery Thickbox plugin. It is a great solution to this problem, especially when you team it up with ColdFusion. Here is a great example.

I want to build a page which will make use of the Thickbox plugin, but I don't want to hard code the images. Instead, I'll let ColdFusion scan a folder and create the list for me. Since I'm using ColdFusion 8, I can also use it to create the thumbnails as well. This means I can copy images right off my camera, dump them in a folder, and leave it at that. I like easy. Let's look at the code.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Untitled Document</title>

<script type="text/javascript" src="http://www.coldfusionjedi.com/js/jquery.js"></script> <script type="text/javascript" src="http://www.coldfusionjedi.com/js/thickbox/thickbox.js"></script> <link rel="stylesheet" href="http://www.coldfusionjedi.com/js/thickbox/thickbox.css" type="text/css" media="screen" /> </head>

<body>

This is the header of the page. Most of it comes right from the default template Dreamweaver made for me. What you really want to care about are the 2 JavaScript includes and the CSS file. These are all the requirements needed for Thickbox.

<cfset imageFolder = "folder2"> <cfset imageDir = expandPath("./#imageFolder#")> <cfdirectory directory="#imageDir#" name="images">

<!--- make thumbs ---> <cfif not directoryExists("#imageDir#/thumbs")> <cfdirectory action="create" directory="#imageDir#/thumbs"> </cfif>

The variable imageFolder, simply refers to the subdirectory where I'm storing the images. The variable imageDir is a full path version of imageFolder. I need both a real full folder for ColdFusion and a relative one for my HTML later on. The cfdirectory tag simply grabs the files in the folder.

I check for a subdirectory named thumbs. If it doesn't exist, I create it. This should only be run once. If you needed to regenerate the thumbnails for whatever reason you can simply delete the folder.

<cfloop query="images">
&lt;!--- valid image? ---&gt;
&lt;cfif isImageFile("#directory#/#name#")&gt;
	&lt;!--- check for thumbnail ---&gt;
	&lt;cfif not fileExists("#directory#/thumbs/#name#")&gt;
		&lt;cfimage action="read" source="#directory#/#name#" name="image"&gt;
		&lt;cfset imageScaleToFit(image, 125, 125)&gt;
		&lt;cfset imageWrite(image, "#directory#/thumbs/#name#",true)&gt;
	&lt;/cfif&gt;
	
	&lt;cfoutput&gt;	
	&lt;a href="#imageFolder#/#name#" title="#name#" class="thickbox" rel="gallery-ss"&gt;&lt;img src="#imageFolder#/thumbs/#name#" alt="#name#" /&gt;&lt;/a&gt;
	&lt;/cfoutput&gt;
&lt;/cfif&gt;

</cfloop>

Now for the complex part (and it really isn't that complex). I loop over the images query returned from the cfdirectory tag. For each file, I check to see if it is a valid image. If so, I then see if the thumbnail exists. If it does not, I read the image in, resize it, and save it in the thumbnails folder.

The last thing to do is output the HTML. I have to use the proper class/rel attributes for Thickbox but the only real dynamic part is the URL used for the link and image tag.

And that's it. You can see this code in action here. I've also zipped the entire thing up and attached it to the blog post. Please download the Thickbox JS code yourself though.

Download attached file.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Katie Atkinson posted on 2/18/2009 at 3:43 PM

I'm so excited by all this... Thanks for bringing JQuery into my life Ray :)

Comment 2 by Curt Gratz posted on 2/18/2009 at 6:23 PM

Ray,

If you want to use the writetobrowser action and resize each image on the fly you can with your imageUtils. <a href="http://imageutils.riaforge....">http://imageutils.riaforge.... using the getURL() method. Just a thought so you don't have to write all the thumbs to disk. Might be expensive depending on the application.

Comment 3 by Eric Cobb posted on 2/18/2009 at 8:00 PM

I used almost this exact same solution a few weeks ago here: http://missga.org/winnergal...

The only difference is I used Lightbox (http://plugins.jquery.com/p... instead of Thickbox. No particular reason why I chose one over the other, I think it was just the first one I found.

Comment 4 by Raymond Camden posted on 2/18/2009 at 8:02 PM

@Curt: I would definitely recommend against that. Resizing is a slow operation at times. I'd only resize once. My method writes to disk just once.

As for getURL, that is for converting a URL into an image, ie, taking a screen shot of a web page. It is not for resizing images.

Comment 5 by Chris posted on 2/19/2009 at 12:22 AM

I will definitely check this out. Have you tried it with a lot of images, say 100?

Comment 6 by Raymond Camden posted on 2/19/2009 at 2:28 AM

I would expect the first hit to be significantly slow. So I'd probably copy 20 at a time. Maybe 50. Of course, once shrunk, it will be much faster.

Comment 7 by Chris Luksha posted on 2/19/2009 at 7:32 PM

Why not - instead of deleting the thumbs folder - just use your little blog cfc trick and put in some kind of reinit key to trigger the last portion of your code? After all the last section only created a thumb if the image did not have one.

So you might do
<cfparam name="url.gogogadgetreset" default="">
<cfswitch expression="url.gogogadgetreset">
<cfcase value="rebuild"> Dump the thumb folder and start over</cfcase>
<cfcase value="refresh">simply refresh the missing thumbs</cfcase>
<cfdefaultcase>do nothing</cfdefaultcase>
</cfswitch>

Just a thought
Chris

Comment 8 by Marwan Narian posted on 2/19/2009 at 8:50 PM

Great work but adding any CF ajax tags breaks it. CF ajax tags seems not to want to work with any other Javascript.

Comment 9 by Raymond Camden posted on 2/19/2009 at 8:52 PM

Nothing in jQuery should 'break' with CFAjax, and vice versa. I'd dig into your code more. Got to be something simple. :)

Comment 10 by wade miller posted on 2/19/2009 at 11:05 PM

After reading your posts about jquery I quickly became a fan, but I have the latest jquery release, and thickbox does not work with it. Only after I used the release you have in this code does it work.

That gives me some concerns about using jquery. I guess nothing is perfect. I am just trying to convince others at my company of its benefits, and this didn't help.

Comment 11 by Raymond Camden posted on 2/19/2009 at 11:08 PM

Wade - I'm using the latest jquery myself and it worked fine with thickbox. I'd try again and see if it was something else.

Comment 12 by Bilgehan posted on 2/20/2009 at 12:12 AM

Although ajax is handy and improves user experience for forms and similar applications, i prefer rest style, easily bookmark-able image galleries.

Comment 13 by wade miller posted on 2/20/2009 at 12:15 AM

Oh, I am about to give up on it. Using jQuery v.1.3.1, the code does not work for me. The larger images do not pull up. Using the version that you reference in the code above, jQuery v. 1.2.6, everything works fine.

I know there is something I'm probably missing. I'm just going to go back to CF.

Comment 14 by Raymond Camden posted on 2/20/2009 at 12:36 AM

@Bilgehan: So what if there was a way to bookmark one of the images? If I did a demo of that, would you approve?

@Wade: Again, my local server was using 1.3.1. Not sure what you mean by saying you will just go back to CF - as this IS CF, CF and JavaScript. :) I wouldn't give up yet. Can you put this online where we can look?

Comment 15 by Bilgehan posted on 2/20/2009 at 1:48 AM

Yes, providing permalinks for the images would be great for accessibility.

Comment 16 by Raymond Camden posted on 2/20/2009 at 1:53 AM

Ok, I've got it on my TODO list. I'm thinking that, by default, you will land on a page and just see the thumbnails, but if you follow the permalink, it will auto load the right image. I can do this - I know I can - just give me few hours. :)

Comment 17 by wade miller posted on 2/20/2009 at 1:57 AM

Okay, here are the links. It is the same exact code except for the jquery.js

http://www.bray.com/tboxtes...

http://www.bray.com/tboxtes...

What I meant by "back to using CF" I left off and actionscript.

Comment 18 by Raymond Camden posted on 2/20/2009 at 2:06 AM

Use Firebug. Go to the net tab, and you will see it fails on

http://www.bray.com/tboxtes...

On the docs for Thickbox, they talk about the fixes you have to do in code for this.

Comment 19 by wade miller posted on 2/20/2009 at 2:16 AM

I looked all over the documentation. Two of us did. I can't believe we missed that. Thank you.

I've been meaning to install Firebug, but I always put it off. Now, I will do it while it is fresh on my mind.

Comment 20 by Hatem Jaber posted on 2/20/2009 at 3:25 AM

@Ray, not sure if you looked at Fancybox, but i've used it and it's a really nice modal for the gallery stuff:

http://fancy.klade.lv/

Comment 21 by Raymond Camden posted on 2/20/2009 at 3:47 AM

That's pretty snazzy.

Comment 22 by Raymond Camden posted on 2/20/2009 at 5:04 PM

@Chris: Yes, that's an idea as well. I started to build a custom tag version of this to make it simpler, but the code is so short I didn't really think it worthwhile.

Comment 23 by Marwan Narian posted on 2/20/2009 at 9:40 PM

Ray, please try to display the images in a cflayout type border as an examples of how things breaks with cf ajax when adding external javascript.

Comment 24 by Raymond Camden posted on 2/21/2009 at 1:10 AM

@Marwan: Well, Thickbox is looking for items that match a class when the page loads. If the cflayout loaded content via Ajax then the content wouldn't be there when thickbox was trying to run it.

Comment 25 by Marwan Narian posted on 2/21/2009 at 1:38 AM

Is doing this loading via ajax? And how do you make this kind of calls work? Excuse my poor Javascript skills. Thanks.

<cflayout type="border">
<cflayoutarea name="whatever" position="center">
<script type="text/javascript" src="http://www.coldfusionjedi.c..."></script>
<script type="text/javascript" src="http://www.coldfusionjedi.c..."></script>
<link rel="stylesheet" href="http://www.coldfusionjedi.c..." type="text/css" media="screen" />
</head>

<body>

<cfset imageFolder = "folder2">
<cfset imageDir = expandPath("./#imageFolder#")>
<cfdirectory directory="#imageDir#" name="images">

<!--- make thumbs --->
<cfif not directoryExists("#imageDir#/thumbs")>
<cfdirectory action="create" directory="#imageDir#/thumbs">
</cfif>

<cfloop query="images">

<!--- valid image? --->
<cfif isImageFile("#directory#/#name#")>
<!--- check for thumbnail --->
<cfif not fileExists("#directory#/thumbs/#name#")>
<cfimage action="read" source="#directory#/#name#" name="image">
<cfset imageScaleToFit(image, 125, 125)>
<cfset imageWrite(image, "#directory#/thumbs/#name#",true)>
</cfif>

<cfoutput>
<a href="#imageFolder#/#name#" title="#name#" class="thickbox" rel="gallery-ss"><img src="#imageFolder#/thumbs/#name#" alt="#name#" /></a>
</cfoutput>
</cfif>
</cfloop>
</cflayoutarea>
</cflayout>

Comment 26 by Raymond Camden posted on 2/22/2009 at 3:01 AM

That code worked ok for me.

Comment 27 by Marwan Narian posted on 2/23/2009 at 8:13 PM

Glad the code works for you. This code and any code that contains cflayout of type border that you insert javascript any where in it stops to work on all 3 of our servers.

Comment 28 by Raymond Camden posted on 2/23/2009 at 8:17 PM

And you used the exact same code? Are you running CF801 with the latest hotfixes?

Comment 29 by Tiffany Trott posted on 3/4/2009 at 8:58 PM

I am experiencing the same problem as Wade Miller. If I use the current 1.3.2 release of jquery the code does not work, revert back to an older version it works fine. I did change the path for macFFBgHack.png and all other paths as well. Any ideas on this? I have experienced this problem on a few of our apps at work as well, they work fine with the older jquery builds but the latest release seems to break them.

Any help would be appreciated!

Comment 30 by Raymond Camden posted on 3/4/2009 at 9:04 PM

I've confirmed - and I'm digging. May have to check with the plugin author.

Comment 31 by Raymond Camden posted on 3/4/2009 at 9:09 PM

Ok, I punted. I contacted the plugin author.

Comment 32 by Raymond Camden posted on 3/4/2009 at 9:11 PM

I should have just checked his forums first:

http://codylindley.com/thic...

I replace the line mentioned and it worked for me.

Comment 33 by Tiffany Trott posted on 3/4/2009 at 9:38 PM

Thank you so much! I guess I could have checked the forums too, but letting others who come across this post know is a good thing as well.

Thanks again Jedi!!!

Comment 34 by Wade Miller posted on 3/5/2009 at 4:40 AM

I had looked, but never found this solution. I had been cheating and including the older jQuery just for this particular plugin. It was working, but I was never happy since I was fudging.

Comment 35 by Clint McKoy posted on 4/22/2010 at 3:10 PM

Awesome and easy... thanks for another great tutorial! Just set this up on a site I'm converting from php to cfm that has many galleries and no database... this made my day a whole lot easier.

Comment 36 by Adam posted on 10/27/2011 at 8:26 PM

Great tutorial! It has helped me immensely. I am wondering about adding captions to describe the images. It seems that the quick and easy way would be to rename the image using the description. Is this wrong or bad? How else should I perform this?

Comment 37 by Raymond Camden posted on 10/28/2011 at 1:55 AM

Well, it might get messy. I mean, this is ok:

A_Picture_Of_My_Dog.jpg

But a caption that was a bit longer would be ugly. I'd maybe consider storing the captions in a db table that related file names to captions.

Comment 38 by misty posted on 5/3/2012 at 11:57 AM

Hi ray, I am using the Fancybox Plugin this way:

<cflayoutarea title="Business Images">
<cfset listid = url.lid>
<cfinclude template="userpics.cfm">
</cflayoutarea>

my userpics.cfm file has 100 pictures and i had created a paging system there, showing 10 Images on a Page

Now the issue is for the first time, it loads Good, when i navigate to another page, it just show the image on full Page

Can u guide a bit.

Code for that included page is like this

<link rel="stylesheet" type="text/css" href="fancybox/jquery.fancybox-1.3.4.css" media="screen" />
<script type="text/javascript" src="fancybox/jquery.fancybox-1.3.4.pack.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("a.zoom").fancybox();

$("a.zoom1").fancybox({
'overlayOpacity' : 0.7,
'overlayColor' : '#FFF'
});

$("a.zoom2").fancybox({
'zoomSpeedIn' : 800,
'zoomSpeedOut' : 800,
'overlayShow' : false
});
});
</script>

<cfoutput>
<cfif startRowBack gt 0>
<a href="#AjaxLink('userpics.cfm?startRow=#startRowBack#&listid=#images.pic_listid#')#"><span title="Back #rowsPerPage# Records"><img src="images/arrow_back.gif" alt="Back #rowsPerPage# Records" border="0"></span></a>
</cfif>
<cfif startRowNext lte totalRows>
<a href="#AjaxLink('userpics.cfm?startRow=#startRowNext#&listid=#images.pic_listid#')#"><span title="Next #rowsPerPage# Records"><img src="images/arrow_next.gif" alt="Next #rowsPerPage# Records" border="0"></span></a>
</cfif>
</cfoutput>

Comment 39 by Raymond Camden posted on 5/3/2012 at 2:40 PM

I think your JavaScript needs to be outside of the cflayoutarea. When you go to page 2, the entire area is being replaced, which means your JS is as well.

Comment 40 by misty posted on 5/3/2012 at 4:12 PM

Even Tried that way, Does notwork, when it moves to Page 2

Is this could be an issue that jquery Dom is redy once and when 2 page is navigated it does not load that again

Comment 41 by Raymond Camden posted on 5/3/2012 at 5:58 PM

Well, you got me. I can dig into this offline if you would like, although it crosses into the paid support category. ;)

TO be honest, I do NOT recommend mixing jQuery in with CF's built in Ajax stuff. I'd get rid of the cflayoutareas.

Comment 42 by misty posted on 5/3/2012 at 7:36 PM

Hi Ray, Thanks for everything

I solved it, Let me share code with you so if this annoying things comes up with someone else they can solve it

just change this code:

<script type="text/javascript">
$(document).ready(function() {
$("a.zoom").fancybox();

$("a.zoom1").fancybox({
'overlayOpacity' : 0.7,
'overlayColor' : '#FFF'
});

$("a.zoom2").fancybox({
'zoomSpeedIn' : 800,
'zoomSpeedOut' : 800,
'overlayShow' : false
});
});
</script> to

<script type="text/javascript">
doFancyBox = function() {
$("a.zoom").fancybox();

$("a.zoom1").fancybox({
'overlayOpacity' : 0.7,
'overlayColor' : '#FFF'
});

$("a.zoom2").fancybox({
'zoomSpeedIn' : 800,
'zoomSpeedOut' : 800,
'overlayShow' : false
});
}
</script>

and write the following in the cflayoutarea tag

<cfset AjaxOnLoad('doFancyBox')>

and Boom it will work

Cheers

:)