Dynamically Evaluating Image Functions In ColdFusion 8

Posted April 24, 2008 at 3:07 PM

Tags: ColdFusion

I was playing around with some ideas when I came across an odd behavior with ColdFusion's Evaluate() method. Now, let me start by saying that I hate the Evaluate() method with a passion and I cringe at the idea of using it; however, I was doing something that involved dynamic execution of built-in ColdFusion methods and Evaluate() is the only way I know of as to how to make that happen (without manually writing out all the use-cases).

So anyway, I went to try to use a ColdFusion 8 image function within Evaluate(). The first one I tried was ImageGetWidth(). This worked just fine. But then, I tried ImageBlur():

 Launch code in new window » Download code as text file »

  • <!--- Read in image. --->
  • <cfset objImage = ImageNew( "./kissy_face.jpg" ) />
  •  
  • <!--- Dynamiclly call blur method on given image. --->
  • <cfset Evaluate( "ImageBlur( objImage )" ) />

... and ColdFusion threw the following error:

coldfusion.runtime.CfErrorWrapper : null null

Seeing the "null null", I figured maybe it had something to do with the fact that ImageBlur() doesn't return a value (while ImageGetWidth() does). That's when I started looking around for other ColdFusion methods that don't return a value and realized that image manipulation functions seemed to be unique in this regard.

And so, I built my own method that returned a null value and tried to dynamically execute it:

 Launch code in new window » Download code as text file »

  • <cffunction
  • name="GetVoid"
  • returntype="void"
  • output="false">
  •  
  • <cfreturn />
  • </cffunction>
  •  
  • <!--- Dynamically evaluate void-function. --->
  • <cfset Evaluate( "GetVoid()" ) />

This runs without error. Apparently, it has nothing to do with whether a value is returned (unless of course built-in functions returns a different kind of VOID than a ColdFusion user defined function).

I started to Google around for some possible answers. I had remembered seeing people use a whole bunch of crazy Java to try and do things like this, but I never understood what was going on and never bookmarked it. That's when I came across a link from a while back on Elliott Sprehn's blog about getting template paths. In his blog post, Elliott explores the Page object that is available from ColdFusion's GetPageContext() method. After CFDumping out this object, it turns out that in ColdFusion 8, all of the built-in methods are available. I don't ever remember seeing this, so it might be new in ColdFusion 8.

For fun, I tried dynamically evaluating the same method but from this new source:

 Launch code in new window » Download code as text file »

  • <!--- Read in image. --->
  • <cfset objImage = ImageNew( "./kissy_face.jpg" ) />
  •  
  • <!--- Dynamiclly call blur method on given image. --->
  • <cfset Evaluate(
  • "GetPageContext().GetPage().ImageBlur( objImage )"
  • ) />

This works just fine. I am not sure why this version works and evaluating the built-in method directly throws a null error. And, I still would love a really nice, clean, easy way to dynamically invoke built-in methods :)

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Apr 26, 2008 at 2:33 AM // reply »
123 Comments

Nope, not new in CF8. The Page object has always had the CF functions. This is because the foundation unit of compiled .cfm and .cfc files is the Page object.

That is, a test.cfm is going to compile into a Java class that extends the coldfusion.runtime.CFPage class, and your calls to functions like ListGetAt() are going to be transformed into a call to the instance method ListGetAt(). This makes transforming cfml code into Java really easy as there's a 1-1 mapping between CF functions and their implementations inside the compiled class. It also makes the guts of the CF runtime simpler with respect to having a unified foundation type; despite the high level difference between custom tags, cfcs and "regular" .cfm files, they're really the same thing to the engine.

This is also the reason that CF won't let you name functions the same as Java methods since there's ambiguity in the call.

Ever wondered what the compiled class name is for your .cfm file?

<cfdump var="#getClass().getName()#">

or #hashCode()# will give you the hashCode for the current Page.

(See http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html)

In this sense CF has a ton of "secret" functions that are Java methods on the Page.

Generally each CF type has corresponding Java classes that have the real implementations of these functions, and the methods you see in the Page are just proxies to them, or setup some default values.

For instance the coldfusion.image.Image class implements the Image CF type, and has methods that match all the CF image functions.

So the below are all the same:

<cfset ImageBlur(objImage)>
<cfset objImage.blur(3)>
<cfset getPageContext().getPage().ImageBlur(objImage)>


Apr 27, 2008 at 12:48 PM // reply »
6,371 Comments

@Elliot,

I was having trouble finding the function methods via GetPageContext() from within a CFC. Any suggestions?


Apr 27, 2008 at 1:54 PM // reply »
123 Comments

@Ben

Not sure what you mean by function methods. Do you mean the functions you declared with <cffunction>?


Apr 27, 2008 at 2:01 PM // reply »
6,371 Comments

@Elliott,

What I mean is that in a CFM page, calling:

GetPageContext().GetPage()

... returns a VERY different object than the same call made from a CFC page. The one called from the CFC page does not seem to have the built-in methods as class methods.


Apr 27, 2008 at 2:06 PM // reply »
6,371 Comments

@Elliott,

To be more clear, I want to be able to call:

GetPageContext().GetPage().ImageBlur()

... from within a CFC call, but cannot.


Apr 27, 2008 at 2:29 PM // reply »
123 Comments

The objects are in fact not different, at least not in that sense. I'm not experiencing the issue you're having either.

The below code illustrates what I'm talking about:

<!---
File: example.cfc

Outside a function there's no magic coldfusion.runtime.CFDummyComponent,
but the Page returned is still of class coldfusion.runtime.CFPage
--->
<cfset variables.actualPage = getPageContext().getPage()>

<!---
Inside a function it's a little different, there's a wrapper around the real
class that represents this page called a "CFDummyComponent", the real
page exists as a package access field on it.

Note that both the CFDummyComponent (which extends CFComponent) and the
actual page extend CFPage, so the CF functions exist on both.
--->
<cffunction name="test">
<cfset var Page = getPageContext().getPage()>
<cfset var actualPageField = Page.getClass().getDeclaredField("actualPage")>
<cfset var actualPage = "">
<cfset var image = ImageNew("http://www.google.com/images/logo_google_suggest.gif")>

<cfset actualPageField.setAccessible(true)>
<cfset actualPage = actualPageField.get(Page)>

<!--- These are all exactly the same, we get a 4 times blurred image --->
<cfset actualPage.ImageBlur(image)>
<cfset variables.actualPage.ImageBlur(image)>
<cfset Page.ImageBlur(image)>
<cfset ImageBlur(image)>

<cfimage action="writetobrowser" source="#image#">
</cffunction>


Apr 27, 2008 at 2:39 PM // reply »
6,371 Comments

@Elliott,

Very interesting. When I CFDump out the GetPageContext().GetPage() in the pseudo-constructor, I do NOT get the built-in ColdFusion methods. However, when I go to USE them, they work fine. It must just not be outputting the data even though it exists. There's probably some "conflict" between the data about the component and about the Java class that ties it all together (and CF is erring on the CF-related data rather than the Java data).

Thank you so much for the tip. I got an interesting little experiment going on here that I will blog about tomorrow.


Apr 27, 2008 at 2:48 PM // reply »
123 Comments

@Ben

You *DO* get the cffunctions, cfdump just isn't printing them, and instead prints that pretty red cfcomponent box with the information about the component.

Try:

<!---
File: example2.cfc

Print out all the CF functions.
--->
<cfset methods = getPageContext().getPage().getClass().getSuperClass().getMethods()>

<cfloop array="#methods#" index="i">
<cfset writeOutput(i)><br>
</cfloop>

They're all there, cfdump is just smart enough to print out cfcomponent pages a little different.


Apr 27, 2008 at 2:53 PM // reply »
6,371 Comments

@Elliott,

Ahhh, thanks. Much appreciated.


Apr 27, 2008 at 2:57 PM // reply »
123 Comments

@Ben

No problem. Can't wait to see what you're cooking up :)


Apr 28, 2008 at 9:24 AM // reply »
6,371 Comments

@Elliott,

Thanks for all your help - it worked like a charm:

http://www.bennadel.com/index.cfm?dax=blog:1212.view


May 9, 2008 at 12:15 PM // reply »
15 Comments

ColdFusion's Evaluate() is Godlike. It is the secret sauce for dyamanic rules engine driven applications. We use it extensively... If you're looking to build a rules based decision engine, you'll need this tool in your arsenal.


May 9, 2008 at 12:25 PM // reply »
6,371 Comments

@Alan,

In the past I have not been much of a fan of the Evaluate() method. I find that I can often get around it by using pointers and better struct notation. However, with something like this, I simply could not find a way around it.

I have not done much in the way of rules based dynamic goodness. Sounds very cool.


May 9, 2008 at 12:52 PM // reply »
15 Comments

@Ben

Sometime I'll have to show you (or perhaps it'd be a worthwile article for other developers). A rules engine puts the capabilities of Cold Fusion in the business automation/workflow class of applications... and totally rocks. Plus there are a lot more things you can use it for too.

Our little company (and loanxengine product) just got selected as a preferred technology partner for LendingTree. We service a number of their lenders already, but LendingTree will be officially outsourcing automatic loan bidding and CRM processes to us!

Image, the next time someone does a loan through LendingTree, they may actually be using Cold Fusion. ;*)

Cool, no? ...And much of it thanks to Evaluate() Cold Fusion Rocks!!


John
Feb 3, 2009 at 3:39 AM // reply »
1 Comments

Hello everybody,

I think my query is related to this topic of discussion. I'm really not sure who else to contact. I have a cfm template which I refer to in the <img> src tag (<img src="OutputImage.cfm" />) . It outputs the image correctly and as I would expect it to. Here is the code:

OutputImage.cfm
----------------

<cfscript>
Context = getPageContext();
Context.setFlushOutput(false);

Response = Context.getResponse().getResponse();
OutputStream = Response.getOutputStream();
Response.setContentType("image/jpeg");

OutputImage(session.sessionid,'en',OutputStream);

OutputStream.flush();
OutputStream.close();
</cfscript>

However, when I move the exact same code to a function in a CFC and call it, nothing but the image gets outputted in the browser. Any ideas why this is the case? Is there a different way to call the GetPageContext() method within a CFC?

Here is the call:

<img src="#request.RenderImage()#" />

Here is the same code in a cfc.

<cfcomponent displayname="ImageRenderer">
<cffunction name="RenderImage" returntype="void" access="public" output="true">
<cfscript>
Context = getPageContext();
Context.setFlushOutput(false);

Response = Context.getResponse().getResponse();
OutputStream = Response.getOutputStream();
Response.setContentType("image/jpeg");

OutputImage(session.sessionid,'en',OutputStream);

OutputStream.flush();
OutputStream.close();
</cfscript>
</cffunction>
</cfcomponent>

I would really appreciate your help.
Regards,
John


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 7, 2009 at 5:53 PM
Ask Ben: Javascript String Replace Method
You can find here an advanced function that prepared with javascript replace function. This can make the first letters of words, sentences, lines and whatever you define automatically: http://www.m ... read »
Andrew Neely
Nov 7, 2009 at 4:56 PM
A Moment That Touched Me - The Fountainhead
Ben, Glad you enjoyed the podcast. Yeah, the Tank Riot guys can get really chatty during the episodes, but that's part of the charm of it for me. They've covered everything from Nichola Tesla to Cha ... read »
Nov 7, 2009 at 4:43 PM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
Is it possible to make some more MenĂ¼`s ? ... read »
Jill
Nov 7, 2009 at 11:40 AM
How To Unformat Your Code (Like A Pro)
Derek, I think you might be right - sweet! Thanks for the link :) ... read »
Nov 7, 2009 at 11:25 AM
How To Unformat Your Code (Like A Pro)
I think it would be way easier to just use this http://www.logichammer.com/html-formatter/ He just released v3 and it rocks. ... read »
Jill
Nov 7, 2009 at 7:58 AM
How To Unformat Your Code (Like A Pro)
LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else' ... read »
Nov 6, 2009 at 10:10 PM
How To Unformat Your Code (Like A Pro)
The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, bu ... read »
Roe
Nov 6, 2009 at 5:11 PM
Passing Arrays By Reference In ColdFusion - SWEEET!
ArraySort also reorders the results of these java obj's ... read »