Best of CF9: MuralBuilder

This post is more than 2 years old.

Welcome to the final entry in the Best of CF9 contest! We are finally done. I'll be posting a wrap up and announcing the winners mid next week. In the meantime, please enjoy this final review written by Charlie Arehart.

Wow, even before I looked at a line of code, I loved MuralBuilder, and not just for the idea or its implementation, but as much for Ben Riordan's style in presenting it.

What it does:

Let's clarify first what it does: it allows you to convert an image into a larger poster, or mural. It can be many times larger. The app does the conversion, using various new CF9 features. Once installed, you can upload an image to it (whose progress is tracked using the new CFProgressBar), select a size for the poster (using the ajax CFSlider--not the old Flash form variant-to pick the size), and its converted into a PDF (using CF's image and PDF manipulation features, and again using CFProgressBar to keep you updated of the status) and the PDF has a greatly expanded image implemented on as many pages as needed to print out to make a mural. Simple and effective.

Evaluation of Entry:

Sure, there have long been other tools to do this, but let's consider why it's a nifty contest entry.

First, it's written in CF, which we all love to see. Second, it's using CF9 features, which is key to getting into the contest. Third, and great to see, is that he's made it an easy and stylish web-accessible service, so you can even run it yourself already (without downloading and installing the code, for free) at http://muralbuilder.com/. But as observers of the contest, you can also get the code.

Better still, if you visit the site (or run the code) you'll notice that he offers a brief (74 second) video right on the front page to introduce it. And it's not a boring walkthrough of code or even benefits. Instead, it opens with a nifty fast-paced video of a wall being covered with the results of the tool. First you see it being printed, then mounted, then back to showing the interface being used. And all this is done without any voiceover, but instead a trippy backbeat and an invisible hand working away. I give that an "A" for style points.

Mural Builder Intro from Ben Riordan on Vimeo.

As for the CF9 features:

As I mentioned above, the app uses the new CFProgressBar and the updated CFSlider (allowing it to be used in other than Flash forms). Beyond the simple interface features of each, Ben also is leveraging their event handling capabilities, so that when each element finishes rendering, the interface knows it can show the next interface control needed to proceed through the process of accepting/converting the uploaded file.

I'll note that he also nicely uses the tooltip feature (which was added in CF8), offering a help icon for each input control. And as another touch of class, there's a feedback link stylishly placed at the left of the page rotated sideways. Nice way to make it present but not obtrusive. Finally, you'll notice there is a "print center" button, which he notes (in a tooltip) that he eventually plans to integrate with printing centers like OfficeDepot, FedEx Office, etc.

And all this from someone who just started doing CF, and indeed development in general, in October with CF9's release. Ben's a designer by profession, so that explains the site's style and the video. But again an A for effort the concept, the site's nice touches, the video, and even his packaging the app up in a way that's easy to use. We could use more past-designers in the CF community! :-)

Picking nits (if I have to)

If I had to pick any nits, here are a few.

I also see that he sets a max upload size of 12mb. It certainly makes sense to set some limit on the site, but someone running it locally might like to change that, so it would be good to expose that up front in the code as a configurable option.

It's worth noting also that CFers don't take enough advantage of using external files to permit such changes. Rather than edit the code, it could read in an ini file where they could be set, as supported by the CF functions GetProfileString, GetProfileSections, and SetProfileString. But I don't begrudge a newcomer not knowing of these, when in fact I'd say most CF developers don't know of them.

It's also not clear what happens to the images (uploaded and generated), whether running the tool on his site or if one implements it on their own. Users (and admins) may wonder how long they stick around. And for the site (and for someone offering the tool locally), users may also wonder about any privacy notice or other terms of use. Just something to consider.

It might also be nice for the upload process to be followed by a display of the image, just to confirm one pointed to the right file to be uploaded. But the image name is shown, and that will surely suffice for most people. And you may notice when you first run it that there's no submit button ("build document", as he labels it). That's because he's not showing it until you change the size slider, which defaults to 0. I think that could confuse some people (only some. Again, I said these were nits.) Maybe it could either default to some size other than 0, or it could show the button but have it greyed out until the selections were made (and if one moused over it with none made, a tooltip could remind them that they've not made any, like he did for the "print center" button).

Finally, if you do get the code to run it for yourself, he's tried to make that easy, too, saying in his entry:

"To run it, just unzip it into your web root, and set the correct variables in Application.cfc wwwroot = your coldfusion wwwroot uploadroot = your coldfusion wwwroot/murals. It is changeable for use of a different drive if needed in a higher load environment CFCTree = path to your coldfusion components folder. There is no database connectivity to set up."

Some readers will know that even that modification can be avoided, if you just use CF's built-in functions or variables to determine that location dynamically. In this case, expandpath() would work, pointing to the current directory when the code runs in application.cfc, so the code which (as he offered it) says:

<cfset application.wwwroot="c:/coldfusion9/wwwroot/muralBuilder"> <cfset application.uploadroot="c:/coldfusion9/wwwroot/muralBuilder/murals">

Could become:

<cfset application.wwwroot="#expandpath(".")#"> <cfset application.uploadroot=application.uploadroot&"\murals">

He also chose to do those settings in the onrequeststart method of application.cfc, with code testing for whether the application.wwwroot variable had been created yet, and if not he then set those variables. Again, some will know that since he's using application.cfc, those settings are something which can instead be done in the onapplicationstart method.

But hey, as I noted above, he did indicate that he was new to CF, so I point these out only for him and others reading this who may benefit.

Conclusion: a 10!

But none of those nits take away from the tool in terms of the contest. For that, I give it a 10, for all the reasons offered above the nits. Great job, Ben Riordan, and welcome to the CF community! :-)

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 Robert S Zehnder posted on 1/21/2010 at 11:52 PM

Now *that* is a pretty slick idea. Good job.

Comment 2 by Patrick Heppler posted on 1/21/2010 at 11:53 PM

Worked only one time. I tried a few times, always with the same image. The uploadify progressbar appears, but nothing happens. Tried to follow the requests with Firebug, 'cause I use uploadify, too. But can't catch any hint. Dunno what's wrong. I'm using Firefox 3.6 on OS X 10.6.2.

When upload fails, the last sent request is:
http://muralbuilder.com/bui...

But it should call includes/uploadify.cfm?random=79TJFZnk65a4nQ

Comment 3 by Patrick Heppler posted on 1/21/2010 at 11:57 PM

Anyway, it's a nice idea, of course! I'd give 10 points, too!

Comment 4 by Ben Nadel posted on 1/22/2010 at 12:12 AM

Cool idea and an outstanding video :) I loved the way the stack of papers moved across the desk and up the wall - brilliant.

Comment 5 by Wookie posted on 1/22/2010 at 1:23 AM

Bloody brilliant! I'm going to try Marissa Miller. :)

Comment 6 by Marko Simic posted on 1/22/2010 at 1:45 AM

Cool. First thing I said when I saw video (and before read the rest of the text) was "This guy must be a designer. This cannot be done by hard core developer " :)))
I mean, I saw creative developers but this is a work of a professional or at least someone who has developed designer skills.

This is a pure proof of CF uberness. Only CF allow entry level developers to create such a cool things.

Keep up the good work, Ben.

Comment 7 by Simon posted on 1/22/2010 at 1:58 AM

That is really cool. I think I'll make a jumbo Mickey mouse for my son's room door.

Comment 8 by Akbarsait posted on 1/22/2010 at 4:20 AM

Really amazing and brilliant work.

Comment 9 by Ben Riordan posted on 1/22/2010 at 5:07 AM

Hey - thank you so much Charlie for your time put into this review!

I was wondering if the application might not be good enough to be reviewed - so I am stoked to see this review and such positive comments. Thanks to you all.

I have seen expandpath() in example code before but had not yet taken the time to explore that function. Now I know :)

I set up the application variables in the onrequest start method because it is how they were set up in various lynda.com tutorials. It is good to now know a more "proper" way to do that.

Good points about privacy issues, Charlie. I included a basic minimally edited outline, but did not specify anything about the images. I will do that.

Anything over an image of a few MB starts to create issues with memory space and creates java heap size errors. That is why I have the 12MB limit as of now. In my hosting environment I don't have control of that, but yes it would be very nice for local versions.

@Patrick -
Charlie had issues with that when he was testing it as well. I could never get the onComplete method of uploadify to work (server settings?) I don't know, but eventually I had to make my own way. I modified the uploadify javascript to comment out the following lines
---
// jQuery("#" + jQuery(this).attr('id') + ID + " .percentage").text(' - Completed');
// jQuery("#" + jQuery(this).attr('id') + ID).fadeOut(250, function() { jQuery(this).remove()});
---
And then monitor the progress percentage with jquery to continue when it reaches 100%. This might be what you are having issues with? It seems to perform differently in different server environments, though I do not know that is the cause for sure. I still haven't really figured it out.

I need to give credit to Ben Nadel - It is documented in the component, but I will say it here as well - I am using one of his components to generate random strings. http://www.bennadel.com/ind...

Going back now to edit the application it does feel a little bit like spaghetti to me so I am currently working on learning CFWheels.

Thanks again to all of you. It was a great pleasure to see this contest when I was starting out with development. It gave me something to work on out of the gate. The ColdFusion blogs that many of you maintain have been an awesome resource.

Ok, my book post is done :).

Comment 10 by Pritesh posted on 1/22/2010 at 9:02 AM

Cool Idea...

Comment 11 by Sam Farmer posted on 1/22/2010 at 9:43 AM

@Ben: Beautiful application and an awesome idea.

@Ray: Thanks for running this competition. Its been wonderful to see how creative fellow CF developers can be.

Comment 12 by Patrick Heppler posted on 1/22/2010 at 3:56 PM

@Ben I remember that I had to modify the uploadify.fla to add cfid and cftoken, 'cause Flash always started it's own session.

On line 338 in uploadify.fla I edited:
if (param.script.substr(0,1) != '/' && param.script.substr(0,4) != 'http') param.script = param.pagepath + param.script+'?cfid='+param.cfid+'&cftoken='+param.cftoken;

And changed the JavaScript:
<script type="text/javascript"><!--
$(document).ready(function() {

$("##uploadify").uploadify({
'uploader' : 'uploadify/scripts/uploadify.swf',
'script' : 'uploadify/scripts/uploadify.cfm&cfid=#session.CFID#&cftoken=#session.cftoken#',
'cancelImg' : 'uploadify/cancel.png',
'folder' : 'uploads',
'queueID' : 'fileQueue',
'buttonText' : 'Upload File',
'fileDesc' : 'Only Pictures and PDF',
'fileExt' :'*.jpg;*.pdf;*.jpeg;*.jpe;*.tiff;*.tif;*.png',
'auto' : true,
'wmode':'transparent',
'multi' : true

});
});
// --></script>

Do you use <cfoutput>1</cfoutput> in your uploadify.cfm after upload is completed? This is needed to tell the JavaScript "All done!"

Comment 13 by Lola LB posted on 1/22/2010 at 5:04 PM

Freaking cool! Just a suggestion . . . you could get the name of the image, and use that as the name of the downloadable pdf instead of a random string of numbers and alphas.

Comment 14 by PB posted on 1/22/2010 at 9:34 PM

@Ray:

Thanks for the awesome daily reading. Small little comment - but shouldn't this code:

cfset application.wwwroot="#expandpath(".")#"
cfset application.uploadroot=application.uploadroot&"\murals"

read like this?

cfset application.wwwroot="#expandpath(".")#"
cfset application.uploadroot=application.wwwroot&"\murals"

Thanks again and thanks to Ben for sharing as well.

Comment 15 by Ben Riordan posted on 1/23/2010 at 5:56 AM

@Patrick
I hadn't performed any of that - very helpful!. Thank you. I'll give it a try. This will be very helpful in future uses of of the uploadify plugin.

In this specific case, since onComplete doesn't register, I used it as a pseudo feature instead. Since the upload bar does not fade away on a completed upload which is the normal documented behavior, I instead opted to change the bar to green to clearly signal a completed upload. If it actually did work I think my finished UI would have been different. Interesting how things like that happen :)

@PB
I'll leave Ray or someone else to answer this for sure since I hadn't used expandpath before, but that looks true to me. application.uploadroot is setting itself as itself before being defined.

Comment 16 by charlie arehart posted on 1/23/2010 at 6:54 AM

@Ben R: again great job, and I'm surprised to hear you had doubts. It's awesome, and I'm glad to see others say so.

@Ben R and Patrick: As for the problem with it not running for Patrick, yeah, as Ben noted I had problems with his first version, but he fixed that, and I happened to have gotten a new computer by the time I tested his second version, and it worked there. If there's an ongoing issue, perhaps it can be sorted out here as current or future readers check it out.

@PB: About that mistake in the suggested change for use of expandpath, yep, my bad. I was focused more on pointing out the opp to change to using expandpath, and though I thought I had tested it out before writing it, somehow I was mistaken.

Some may also note that I could (and should) have thought to remove the quotes and pounds in the setting of wwwroot, when I removed his static value. Doh! :-) I did get that right it in the second cfset, of course.

So it could be:

cfset application.wwwroot=expandpath(".")

cfset application.uploadroot=application.wwwroot&"\murals"

Now, some might reasonably prefer to have written that second assignment to go ahead and USE the quotes and pounds (and not use the ampersand), as in:

cfset application.uploadroot="#application.wwwroot#\murals"

That's just stylistic differences. But thanks for catching my mistake in the second assignment.

Looking forward to seeing how the actual contest voting goes. Great idea and great effort, Ray, contestants, and reviewers.

Comment 17 by Gary Gilbert posted on 1/25/2010 at 12:31 AM

@Charlie,

If I were to nit-pick I would mention that ColdFusion is a Java Based language where backslashes don't have a place :)

cfset application.uploadroot = "#application.wwwroot#/murals"

But I don't nit-pick, so I won't say that ;)

@Ben -> Fantasic job on the mural builder, now to find the right picture ....

Comment 18 by Charlie Arehart posted on 1/30/2010 at 9:40 PM

Yep, fair enough, Gary. You caught me being a sloppy Windows guy. :-) We're all learning things in these comments.

And since we started commenting, Ben has since been declared the winner (http://www.coldfusionjedi.c.... Awesome to hear, and I'm really happy to have had the chance to do the review it. Congrats, Ben!