Dynamically Evaluating Image Functions In ColdFusion 8

Posted April 24, 2008 at 3:07 PM by Ben Nadel

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():

  • <!--- 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:

  • <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:

  • <!--- 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 :)




Reader Comments

Apr 26, 2008 at 2:33 AM // reply »
132 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 »
11,314 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 »
132 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 »
11,314 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 »
11,314 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 »
132 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 »
11,314 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 »
132 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 »
11,314 Comments

@Elliott,

Ahhh, thanks. Much appreciated.


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

@Ben

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


Apr 28, 2008 at 9:24 AM // reply »
11,314 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 »
16 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 »
11,314 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 »
16 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!!


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 A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 19, 2013 at 9:38 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Alesei, Glad you like it. Even after working with AngularJS for months, I still get a bunch of unexpected, "$digest is already in progress". So hard to debug sometimes! ... read »
Jun 19, 2013 at 9:36 PM
Working With Inherited Collections In AngularJS
@Mike, The relationship of $scope values is definitely an interesting thing! But it's not simple - it really forces you to understand prototypal inheritance, which is not at all a simple topic! Gla ... read »
Jun 19, 2013 at 9:35 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
@Joe, Oh, super interesting! I had only thought to url-encode the signature; but I think that's because the S3 docs actually have a special NOTE telling you to do so. It would have never occurred t ... read »
Jun 19, 2013 at 9:32 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
@Richard, Glad you like! Hopefully I'll have some more interesting stuff coming. This morning, I blogged a bit more about generating the pre-signed, query string authenticated URLs; but, then deeme ... read »
Jun 19, 2013 at 9:31 PM
Filter vs. ngHide With ngRepeat In AngularJS
@Mike, Honestly, in the majority of cases, I would say there isn't going to be a difference. Both approaches have trade-offs. If you use the filter, then you have fewer DOM elements and fewer $scop ... read »
Jun 19, 2013 at 2:01 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
I have coincidentally been beating my head against the S3 API for the last week or so. One big "gotcha" I had to work around was file names and paths containing spaces. Remember to URL Enco ... read »
Jun 19, 2013 at 1:27 PM
Using Slice(), Substring(), And Substr() In Javascript
very good article. By the way IE supports negative values in substr or slice in verson 10. ... read »
Jun 19, 2013 at 11:33 AM
Filter vs. ngHide With ngRepeat In AngularJS
In your assessment, is it correct to say that given a list of say 500 items its more performant to use the `ngHide` method over the `filter` method? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools