Building a Simple Image Manager with tmt_image
Posted on Dec 11, 2005
Two of the greatest benefits of open-source software is that it is updated frequently and that you can modify the source to suit your needs. However, often these two benefits are somewhat incompatible; once you modify the source, keeping up with the constant updates can be difficult. Such is the case with the FCKEditor, while it is (IMHO) the best and most feature rich WYSIWYG editor out there, its image management is missing some features - of utmost importance to your non-"web-savvy" user is image resizing. However, I know from experience that once you modify the image management source, keeping the editor up-to-date can become daunting. For those projects that are tightly budget constrained and cannot afford Alagad's image component, fortunately Massimo Foti has created the free (not open-source - see license) tmt_image component. I have created a very basic image manager that allows you to upload, resize and delete images from a folder to demonstrate how you can use tmt_image to get the dimensions of an image and resize it.First, as I always do, some caveats... This is a very quick and dirty little application, and is by no means full-featured; if you run it on a folder with alot of images it may well just crap-out for all I know as it isn't meant to handle that...oh and it doesn't allow any directory management, so your images all get dumped in the same folder. However for those of you who are so inclined, I have included a zip (download link) of the code that you can expand on however you like (you will need to download and place tmt_image in there due to licensing).
Reviewing the Code
First, I created a udf library file with two UDF's from CFLib. the first is FncFileSize, which converts a file size in bytes to a more readable format. The second is getRelative, which we will use to convert the absolute file path returned by a cfdirectory query into a relative path. The last UDF is a simple javascript alert function to allow me to call a js alert from cfscript:
function alert(message) { writeOutput("<script language='javascript'>alert('" & message & "');</script>"); }
The form itself will just run a cfdirectory on a specified image folder and will list all the images in the given folder with their current file size, height and width. Clicking on an image will open a preview window the height and width of the image. The form will allow you to resize any image simply by changing its width and submitting with the resize button. The form will have a delete button next to each image and will also allow you to upload new images to the folder. Like I said before, this is some pretty basic functionality. Here's the code:
<cfinclude template="lib.cfm" /> <P>
<cfif isDefined("form.uploadImage")> <cffile action="upload" filefield="uploadImage" destination="#expandPath('img')#" /> <cfelseif isDefined("form.delete") AND fileExists(form.fileLoc)> <cffile action="delete" file="#form.fileLoc#"> </cfif> <P>
<cfscript> imgObj=CreateObject("component", "com.tmt_img"); <P>
if (isDefined("form.resize")) { if (NOT isNumeric(form.newWidth)) { alert("Please be sure the width you entered is numeric"); } else if (imgObj.getWidth(form.fileLoc) EQ form.newWidth) { alert("The image is already the width specified"); } else { imgObj.resize("#form.fileLoc#", "#form.fileLoc#", form.newWidth); } } </cfscript> <P>
<cfdirectory action="list" directory="#expandPath('img')#" name="qryImages" /> <P>
<!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> <InvalidTag http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>image manager</title> <style type="text/css"> BODY { font-family : Arial, Helvetica, sans-serif; font-size : 10pt; background-color: #FFFFFF; } #main TABLE { border : 1px solid #000000; width: 580px; } #main TH { border-bottom: 1px solid #000000; background-color: #CCCCCC; } #main INPUT { border: 1px solid #000000; } </style> </head> <P>
<body> <div id="main"> <cfoutput> <form name="imageForm" method="post" action="#CGI.SCRIPT_NAME#" enctype="multipart/form-data"> Upload:&nbsp;<input type="file" name="uploadImage" />&nbsp;<input type="submit" name="submit" value="Upload" /> </form> <P>
<table border="0" cellpadding="3" cellspacing="0"> <tr> <th>Image File</th> <th>Size</th> <th>Height</th> <th>Width</th> <th>Resize</th> <th>Delete</th> </tr> <cfif qryImages.recordCount EQ 0> <tr> <td colspan="5">No existing images</td> </tr> </cfif> <cfloop query="qryImages"> <form name="resizeForm#qryImages.currentRow#" action="#CGI.SCRIPT_NAME#" method="post"> <cfset theDirectory = expandPath('img')> <cftry> <tr> <td><a href="##" onclick="window.open('#getRelative(qryImages.directory)#/#qryImages.name#','show','width=#imgObj.getWidth('#theDirectory#/#qryImages.name#')#,height=#imgObj.getHeight('#theDirectory#/#qryImages.name#')#')">#qryImages.name#</a> <input type="hidden" name="fileLoc" value="#qryImages.directory#/#qryImages.name#"></td> <td align="center">#fncFileSize(qryImages.size)#</td> <td align="center">#imgObj.getHeight('#qryImages.directory#/#qryImages.name#')#</td> <td align="center"><input type="text" name="newWidth" size="4" maxlength="4" value="#imgObj.getWidth('#theDirectory#/#qryImages.name#')#" /></td> <td align="center"><input type="submit" name="resize" value="Resize" /></td> <td align="center"><input type="submit" name="delete" value="Delete" /></td> </tr> <cfcatch type="any"> <tr> <td><a href="##" onclick="window.open('#getRelative(qryImages.directory)#/#qryImages.name#','show','width=300,height=300,scrollbars')">#qryImages.name#</a> <input type="hidden" name="fileLoc" value="#qryImages.directory#/#qryImages.name#"></td> <td align="center">#fncFileSize(qryImages.size)#</td> <td colspan="3" align="center">cannot read file</td> <td align="center"><input type="submit" name="delete" value="Delete" /></td> </tr> </cfcatch> </cftry> </form> </cfloop> </table> </cfoutput> </div> </body> </html>
After including the UDF library, you'll see some basic code that simply uploads or deletes a file specified in the form. The following cfscript block contains the all the code you need to use tmt_image to resize your image using its resize() method (plus some basic error checking). Pretty simple eh? First, we check to see that you actually specified a numeric width (duh!) and then to see if the image is already resized to the size you specified (you could also check if it is smaller if you want to disallow enlarging since this can result in a huge quality loss). You will note that we are accessing the current width of the image using tmt_image's getWidth() function. Finally, if everything checks out, we resize the image by passing the image as both the source and destination (as in the resized image will overwrite the original) and the new width.
The rest of the code should be pretty basic. The only thing is that you will see that I wrap my form loop in a cftry/catch block. This is because tmt_image only works for JPG and PNG images (and will error out on other file types), but the image manager will allow you to upload and delete images in other formats such as GIF.
Conclusion
I have only touched on a couple of the image management functions available using tmt_image (for instance, it also allows for cropping an image). In the cases where I have used this, I have been pleased with the image quality of the resized images, and, as you can see, it couldn't be any easier to implement. (p.s. enjoy the pics of my son Luke in the zip!).
Comments
Not that I can't go and download the tmt_img.cfc myself, but one would think that the download link is fully functional... and the com folder is empty.
cheers
-Rob
Posted By Rob Gonda / Posted on 12/11/2005 at 12:06 PM
Brian, btw, I meant to ask this in the previous comment ... how is the quality of tmt_img? I stopped using Alagad's image component because the quality wasn't good enough. I had to switch to aspJpg and use it with COM object calls ... and it's not even comparable. Let me know what you think.
-Rob
Posted By Rob Gonda / Posted on 12/11/2005 at 12:09 PM
tmt_img is free, but it's not open source. So you are free to use it but not distribute it. That's why Brian left it out from the zip file.
As for quality, I have no idea how it compare to Alagad or aspJpg. I would suggest to give it a try and see if it fits your needs.
Massimo
Posted By Massimo Foti / Posted on 12/11/2005 at 1:03 PM
Personally, I have found the quality to be fine, but then I never really had an issue with the Alagad image component either.
Posted By Brian Rinaldi / Posted on 12/11/2005 at 2:23 PM
In your first code block, the tag you meant to type was replaced with InvalidTag. I'm assuming you have script protection turned on.
Posted By Raymond Camden / Posted on 12/12/2005 at 5:27 AM
Thanks for pointing that out Ray. It was a script tag...the code has been fixed.
Posted By Brian Rinaldi / Posted on 12/12/2005 at 6:41 AM