ColdFusion 8 Image Manipulation Web Service

Posted March 6, 2008 at 7:00 AM by Ben Nadel

Tags: ColdFusion

The other day, I was talking to my friend and technology cohort, David Stamm, who was having a development environment issue. Basically, he was doing some work on a ColdFusion 7 box and needed to do some image manipulation. Having been on a ColdFusion 8 box for a while, I felt out of touch with the CF7 world and I didn't even know what to recommend. He ended up going with Rick Root's Image.cfc up on RIAForge.org; but, the whole thing got me thinking about distributed image manipulation. I did a quick Google search to see if there were any existing image manipulation web services. I didn't find anything. I took a look on www.xmethods.net to see if there were any there - a few CAPTCHA methods and a conversion method, but nothing substantial.

It seems that there are no image manipulation web services, so, I thought I would take a crack at building one that wraps around ColdFusion 8's built-in image manipulation functionality. I am very new to creating both web services and APIs, so I wanted to keep it simple. I didn't even bother looking up any web service "best practices" or SOAP standards because I wanted to see how simple I could possibly make this API. And to me, when it comes to structured data, there's nothing more straightforward than a light weight XML packet.

When you send the image manipulation commands via XML, you can't send the image binary; XML only supports text-based data. As a result, you need to encode the image binary in Base64 format. I assume that this ability is part of most any programming language. Here is what a sample XML post would look like:

  • <request>
  • <image>
  • <data>.....base64..data.....</data>
  • </image>
  • <commands>
  • <command ..... />
  • <command ..... />
  • <command ..... />
  • <command ..... />
  • </commands>
  • <export format="jpg" quality=".8" />
  • </request>

There is very little extraneous data here. I am passing in the image data in Base64 format. Then, I pass a list of command nodes which will define how the image is manipulated. Then, finally, I pass an export node that defines how the image will be returned (the image is returned in Base64 encoded as well).

When the data comes back from the web service, it either comes back as a successful process or a failure. These are have two different but extremely simple XML structures. The failure looks like this:

  • <response success="no">
  • <error>
  • <message>.....</message>
  • <detail>.....</detail>
  • </error>
  • </response>

... and the successful return looks like this:

  • <response success="yes">
  • <image>
  • <data>.....base64..data.....</data>
  • </image>
  • </response>

The successful response returns the new image in Base64 encoding.

Now, like I said, I know this doesn't stick to any web service standards, but this seems really simple and straightforward to me. I am not sure what benefit adding something like a SOAP wrapper or an XML-RPC style formatting would add (but if you have a good argument, please let me know and I can update it).

I am not supporting a lot of different commands at this time (I wrote this last night and this morning). This is more a proof of concept and to see if anyone would be interested in having me flesh this out any more than it is. Right now, these are the command nodes that I support:

  • <command
  • name="blur"
  • radius="[3-10]"
  • />
  •  
  • <command
  • name="border"
  • color=""
  • thickness="px"
  • />
  •  
  • <command
  • name="flip"
  • direction="vertical|horizontal|diagonal|antidiagonal"
  • />
  •  
  • <command
  • name="grayscale"
  • />
  •  
  • <command
  • name="negative"
  • />
  •  
  • <command
  • name="resize"
  • width="px|%"
  • heigh="px|%"
  • />
  •  
  • <command
  • name="rotate"
  • angle=""
  • />
  •  
  • <command
  • name="scaletofit"
  • width="px"
  • height="px"
  • />
  •  
  • <command
  • name="sharpen"
  • gain="[-1-2]"
  • />

It's a small subset of ColdFusion 8's image manipulation functionality, but enough to do some cool stuff (such as creating thumbnails for user-uploaded images). Now that you see how the API works and what commands are available, let's play around with it a little bit. Let's take the following image and use the image manipulation service to modify it:


 
 
 

 
Two Naughty Girls Touching Each Other In Their Panties  
 
 
 

If you want to play around with this at all, the image manipulation web service URL is:
http://www.bennadel.com/resources/webservices/image/

The following demonstration uses ColdFusion 7 functionality to post XML to my image manipulation web service:

  • <!--- Read in the binary image data. --->
  • <cffile
  • action="readbinary"
  • file="#ExpandPath( './two_naughty_girls_touching.jpg' )#"
  • variable="binImage"
  • />
  •  
  •  
  • <!--- Create the XML request data. --->
  • <cfxml variable="xmlRequest">
  • <cfoutput>
  •  
  • <request>
  • <!--- The image data in Base64 format. --->
  • <image>
  • <data>#ToBase64( binImage )#</data>
  • </image>
  •  
  • <!--- The commands to perform on the image. --->
  • <commands>
  • <command name="resize" width="90%" height="90%" />
  • <command name="flip" direction="horizontal" />
  • <command name="negative" />
  • <command name="border" color="##739EBD" thickness="10" />
  • </commands>
  •  
  • <!--- The format of the returned image. --->
  • <export format="jpg" quality=".8" />
  • </request>
  •  
  • </cfoutput>
  • </cfxml>
  •  
  •  
  • <!--- Post the XML request. --->
  • <cfhttp
  • url="http://www.bennadel.com/resources/webservices/image/"
  • method="post"
  • result="objGet">
  •  
  • <!---
  • Post XML as xml param. This will set the body and
  • the appropriate mime-type.
  • --->
  • <cfhttpparam
  • type="xml"
  • value="#xmlRequest#"
  • />
  •  
  • </cfhttp>
  •  
  •  
  • <!--- Parse the response file content XML. --->
  • <cfset xmlResponse = XmlParse( objGet.FileContent ) />
  •  
  • <!--- Check to see if it was successful. --->
  • <cfif xmlResponse.response.XmlAttributes.success>
  •  
  • <!---
  • Convert the Base64 image data back to binary and then
  • write it to the file system.
  • --->
  • <cffile
  • action="write"
  • file="#ExpandPath( './result.jpg' )#"
  • output="#ToBinary( xmlResponse.response.image.data.XmlText )#"
  • />
  •  
  • <!--- Display new image. --->
  • <img src="./result.jpg" />
  •  
  • <cfelse>
  •  
  • <p>
  • An error occurred.
  • </p>
  •  
  • <p>
  • #xmlResponse.response.error.message.XmlText#
  • </p>
  •  
  • <p>
  • #xmlResponse.response.error.detail.XmlText#
  • </p>
  •  
  • </cfif>

As you can see, we are reading in the image binary and then creating the simple XML packet using ColdFusion 7's CFXml tag. This XML data is then posted to the image manipulation web service using the CFHttp tag with a single CFHttpParam tag. Take special note that we are POSTing the data, not GETting it. POSTing is required for the web service to get access to the document body.

Once the web service returns, we check to see if there was an error (as denoted by the success attribute). If it is successful, we take the returned Base64 data and write it as binary to the file system. Then, just to make sure that everything worked well, I am displaying the image using a standard HTML IMG tag.

Running the above code, we get the following output (new image):


 
 
 

 
Two Naughty Girls Touching Each Other In Panties After Photo Manipulation  
 
 
 

As you can see, the remote call to my image manipulation web service took the given commands and returned the new image. I thought this was kind of a cool idea and very easy to use (from the XML-API view point). Any one have any thoughts on it? Think it is worth pursuing? One of the things that I really like about this idea is that it is language independent - anyone who can create an XML packet and post it can leverage the power of ColdFusion 8's image manipulation functionality. As you know, I love ColdFusion 8 and I want to get it out there, helping as many people as possible.



Reader Comments

Mar 6, 2008 at 8:19 AM // reply »
211 Comments

I definitely think it's worth perusing, but I don't think it should be a free service. Those image libraries are pretty taxing and the speed of them isn't as great as it could be. It's fast when there's 1-2 requests, but this would definitely create a queue of requests quickly if you don't put a floodgate in somewhere.


Mar 6, 2008 at 8:20 AM // reply »
34 Comments

There must be something going around--and maybe it's called CF 8 (grin)--but a lot of folks have been messing around with the new image functions lately. You did your ImageUtils.cfc and now this web service, and both Joshua Cyr and I have developed JavaScript-powered tools for letting end-users arrange text and color on top of existing images and then convey that data to the image functions.

I like this service idea of yours. But given that each webservice call contains the data for an entire image, do you think it would scale up if the service got heavy use or if folks transmitted large, print-quality images for manipulation?


Mar 6, 2008 at 8:22 AM // reply »
43 Comments

this is really cool ben.


Mar 6, 2008 at 8:31 AM // reply »
48 Comments

Very nice!

It would be nice to take this approach to take advantage of the image manipulation on CF8 from servers that haven't upgraded yet.


Mar 6, 2008 at 8:48 AM // reply »
34 Comments

Maybe I should have my image site start using your service. :-)

Regarding the processing power, it would be simple enough to have to submit an app ID with the request which you authenticate, so at least you know who is doing what. You could even limit it to x number of requests a day like amazon does.

Services like this are handy for CMS's and distributed apps where you don't always know what the server has available. So pinging another server for actions like this, or spell checking, then returning result is quite handy. I haven't played with AIR (yet), but I can imagine it could be useful in that regard too.

Speaking of which... spellchecking. Now that is something begging a solution in CF I think. Other than tapping into aspell or the like.


Mar 6, 2008 at 8:53 AM // reply »
10,640 Comments

@All,

Yeah, this was more a proof of concept than anything else. I wanted to see if would get any sort of traction or if it would just get ignored. I think it is definitely something that, if implemented correctly would require some sort of DeveloperID or something such that you would need to sign up for the service and your usage could be tracked.

Now that I see how a Base64 image can be transmitted over a web service and returned, the rest is just figuring out how to make it better.

@Brian,

I would think (*hope*) that is someone is dealing with large, print-quality images, they are not using web-based photo manipulation... but that is a good point. I could easily put a file size limit on the data.


Mar 6, 2008 at 9:01 AM // reply »
211 Comments

@Ben: Putting a file size doesn't help. You had to "accept" that asinine file size first before you could get it all and reject it. I wish CF had a way to throttle the incoming request and if it exceeded the max buffer size, throw an exception.


Mar 6, 2008 at 9:07 AM // reply »
10,640 Comments

@Todd,

True, ColdFusion would still have to accept the file, but at least I could prevent the processing from taking place.


Mar 6, 2008 at 9:35 AM // reply »
43 Comments

i just thought of this, but maybe what you can do Ben is use Amazon's EC2 and S3 services to put something together.

You could probably start a slew of these. I know a lot of people would also love a cfdocument type webservice.


Mar 6, 2008 at 9:39 AM // reply »
211 Comments

Yeah, if you use Amazon cloud services, better have some $... er I mean ¬.


Mar 6, 2008 at 9:46 AM // reply »
10,640 Comments

@Todd,

I never even though of going beyond images... very interesting. Unfortunately, I think document creation is far to processing intensive to be viable in this way.


Mar 6, 2008 at 9:48 AM // reply »
211 Comments

@Ben: I think you meant Tony, not me. :)


Mar 6, 2008 at 9:51 AM // reply »
10,640 Comments

@Todd,

Oops, sorry. I read your comment on my way to reply to his :) Got my brain confused.


Mar 6, 2008 at 10:18 AM // reply »
43 Comments

@todd,

that's why you charge something on a per usage basis or a monthly fee. If anyone know if Railo has a cfimage, then your set Ben.

Railo community is free to use for any use and they support the cfdocument tag.


Mar 6, 2008 at 10:24 AM // reply »
211 Comments

@Tony: From everything I'm reading online from people that switched to the Amazon cloud, it went something like this.

Dev 1: We need to scale quickly!
Dev 2: Amazon to the rescue!
Dev 1: Well, that was easy enough.
-- time passes --
Dev 1: Holy F'ing crap?! $10,000 bill from Amazon?!
Dev 2: Maybe we scaled too much?

heh. Yeah, ad income aren't enough to pay for S3 service. It'd have to be a pay-per-usage thing.


Mar 7, 2008 at 2:49 PM // reply »
34 Comments

Ben,

Nice, though you could have warned about the image, lol. Looking at the site at work, well ummm.........


Oct 1, 2008 at 12:01 PM // reply »
1 Comments

I need this ! Is there any free (or commerical) service that's like it available ?


Apr 24, 2010 at 12:50 AM // reply »
1 Comments

I want you....


May 6, 2010 at 9:46 AM // reply »
1 Comments

Thanks for the answer you guys are still awesome


May 29, 2010 at 6:24 AM // reply »
1 Comments

hot!!!


May 30, 2010 at 11:45 PM // reply »
1 Comments

Regarding the processing power, it would be simple enough to have to submit an app ID with the request which you authenticate, so at least you know who is doing what. You could even limit it to x number of requests a day like amazon does.

Services like this are handy for CMS's and distributed apps where you


Sep 13, 2010 at 6:48 PM // reply »
1 Comments

Realynice sexy girl


Nov 14, 2010 at 1:24 PM // reply »
1 Comments

I haven't tried the code yet but the picture is awesome. :)


Dec 6, 2010 at 11:12 AM // reply »
1 Comments

Wow, nice man..


Dec 17, 2010 at 1:58 PM // reply »
1 Comments

this is cool



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
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »
Feb 9, 2012 at 10:29 PM
Learning ColdFusion 9: Application-Specific Data Sources
@Ben, No offence, but if people were really wanting advanced features they would be using a platform like ASP.NET MVC. CFML is so structurally compromised as a tag-based scripting language that ... read »
Feb 9, 2012 at 10:03 PM
Subversion - Cleanup Failed To Process The Following Paths
@Leviaguirre, do you still have problems with this? ... read »