ColdFusion 8 has a load of awesome image manipulation functionality. So much so, in fact, that it will take several articles to discuss it in any sort of decent way.
In Part 1 of this article (CFDJ, Vol. 9, issue 5), we spent the entire post just exploring all the ways in which ColdFusion 8 can read in and write out/save images. If you haven't read that already, do so now because I won't be explaining the reading/writing of images going forward (I'm assuming that you already understand all the crazy, awesome combinations of ways in which this can be done).
Just as with the reading and writing, image manipulation can be done through both the ColdFusion 8 CFImage tag and through the ColdFusion 8 image manipulation functions. In Part 2, I am going to focus on all the stuff that you can accomplish with just the CFImage tag (and a few of the functions). The CFImage tag provides a very small subset of all that can be done, so I figured it would make for a good primer on manipulation.
In addition to the reading and writing of images, the ColdFusion 8 CFImage tag provides these image manipulation functions:
To help present these image manipulation features a little more clearly, I've created a function called AddImageInfo(). This user-defined ColdFusion function takes in a ColdFusion image object and writes the width and height of the image to the top-left corner of the graphic. This will help us see how the size of the image changes as we manipulate it. The algorithm of the AddImageInfo() function goes beyond the scope of this CFImage article but, hopefully, seeing some of this in Listing 1 will get you more excited about the ColdFusion 8 image editing possibilities.
Even though it's not entirely relevant to this article, there is something I would like to go into a tad bit of detail about (regarding the above UDF) because at first it was throwing me for a loop. Once I get the ColdFusion image object passed in the AddImageInfo() function, I create a copy of it using the ImageCopy() method. I do this because I don't want to corrupt the image that was passed in as it was passed in by reference (not by value).
At first, I thought I would just copy the image using the CFImage tag:
<!---
Copy the image and overwrite the passed in argument
value. Since ColdFusion images are passed around by
reference, this should create a COPY of the image and
then save that new image reference over the one that
was passed in.
--->
<cfimage
action="read"
source="#ARGUMENTS.Image#"
name="ARGUMENTS.Image"
/>
Notice that we are reading in the passed-in ColdFusion image object and then overwriting the ARGUMENTS.Image value. This should have created a new variable value, thereby detaching this reference from the image that was passed in. However, ColdFusion is doing something very strange here - CFImage[ action=read ] does not copy the image to a new variable; it seems to be copying the image data back into the existing variable. To see this in action, take a look at this UDF in Listing 2.
Notice that I am supposedly overwriting the passed in argument with a duplicate of it. Okay, now let's put it into action in Listing 3.
Notice that we are altering the image as we write it to the browser. Since we creating a copy of the image in the UDF, each outputted image should only have one line on it. However, when we run the above code, we get the images shown in Figure 1.
Notice that each AlterImage() call updated the original image data such that each subsequent call built on top of the previous one. Clearly, our CFImage[ action=read ] is not overwriting the variable, ARGUMENTS.Image. This got me thinking - is this complicated by the fact that it was a function or something? I figured I would try this without using a UDF (see Listing 4).
Notice here that we are reading in the image but storing it into a new variable name (objImage versus objNewImage). If this works the same way as the preceding example, objImage and objNewImage should point to the same image data. Yet, when we run the above code, we get the images shown in Figure 2.
In this case, the two variables, objImage and objNewImage, point to independent copies of the image. We know this because, if they pointed to the same image, a border applied to one would show up in both WriteToBrowser tags.
This is very strange behavior, and it feels to me like a bug in the way CFImage handles variable names that overwrite themselves. Anyway, just be careful when reading one image into another image as it might not always do what you expect it to. Just so you know, to make sure I wasn't crazy, I tried something similar with query-based function where the I ran a query that overwrites itself:
<cfquery name="ARGUMENTS.Query" dbtype="query">
SELECT
*
FROM
Query
</cfquery>
Notice that I am overwriting ARGUMENTS.Query by running a query of
queries on ARGUMENTS.Query. This was the closest thing I could think of
that would duplicate the "situation" but with a different data type.
This works just as you would expect it to (creating a new copy of the
query; leaving the original alone).
Sorry about the huge tangent, but I felt that it was important to cover
since we are covering tag-based image manipulation. Now that we are
done with that, we can actually start to explore the CFImage tag
functionality. To start with, let's just read in the mud monster image
and output it with its added data (notice that I will be running all
images through the AddImageInfo() UDF upon output):
<!--- Read in the original image. --->
<cfimage
action="read"
source="./mud_monster.jpg"
name="objOriginalImage"
/>
<!--- Write the origianl to the browser. --->
<cfimage
action="writetobrowser"
source="#AddImageInfo( objOriginalImage )#"
/>
Running the above, we get the image shown in Figure 3.
CFImage - Add Border to Image
When using CFImage to add a border, the related attributes (in addition to the standard CFImage attributes) are:
Black :: ##000000
Blue :: ##0000FF
Red :: ##FF0000
Gray :: ##808080
LightGray :: ##D3D3D3
DarkGray :: ##A9A9A9
Green :: ##008000
Pink :: ##FFC0CB
Cyan :: ##00FFFF
Magenta :: ##FF00FF
Orange :: ##FFA500
White :: ##FFFFFF
Yellow :: ##FFFF00
We are using the double hash (##) in the color names because when they are used as tag attributes, ColdFusion is going to try to evaluate the stuff between hash signs. What's going on here is that the double hash is just an escaped hash in the tag attribute. The border color defaults to black if you don't include it.
The thickness is the width of the border in pixels. This defaults to 1 if you don't include it.
Let see it in action:
<!---
Take the original image and add a border (save
it into a new image variable).
--->
<cfimage
action="border"
source="#objOriginalImage#"
color="##333355"
thickness="2"
name="objImage"
/>
<!--- Write the new image to the browser. --->
<cfimage
action="writetobrowser"
source="#AddImageInfo( objImage )#"
/>
When we run that, we get the image shown in Figure 4.
Notice that this new image is bigger in dimension to the original image. When adding a border, the border gets added to existing image, there by increasing its height and width by double the thickness of the rule.
CFImage - Resize Image
When using CFImage to resize an image, the related attributes (in addition to the standard CFImage attributes) are:
Height
Width
These attributes are both required and can be either in
pixels (just the number) or in percentage (the number followed by the
percent sign). In order for you to maintain the aspect ratio, you must
do your own math if you use pixels. If you want to use percentages,
then just use the same percentage for each attribute. (Note: When using
the ImageResize() function, you don't need to include both values.)
Let's see it in action:
<!---
Take the modified image and resize it 75% of
it's original size.
--->
<cfimage
action="resize"
source="#objImage#"
height="75%"
width="75%"
name="objImage"
/>
<!--- Write the new image to the browser. --->
<cfimage
action="writetobrowser"
source="#AddImageInfo( objImage )#"
/>
When we run that, we get the image shown in Figure 5.
CFImage - Rotate Image
When using CFImage to rotate an image, the related attributes (in addition to the standard CFImage attributes) are:
Angle
Angle is the number of degrees to rotate the image in a clockwise fashion. There are two kinds of rotational actions: 90 degree rotations and non-90 degree rotations. Let's take a look at a 90 degree rotation in action:
<!---
Take the modified image and rotate it 180 degrees.
This will essentially flip the image up-side-down.
--->
<cfimage
action="rotate"
source="#objImage#"
angle="180"
name="objImage"
/>
<!--- Write the new image to the browser. --->
<cfimage
action="writetobrowser"
source="#AddImageInfo( objImage )#"
/>
This rotates the image by a multiple of 90 degrees (180 degrees), which will basically flip the image up-side-down, giving us the image shown in Figure 6.
When you rotate an image to something other than a multiple of 90 degrees, the problem you get is that the image no longer fits nicely on the existing canvas. For this to work, the canvas size has to increase to accommodate the diagonal width of the graphic. Let's give it a go:
<!---
Take the modified image and rotate it 225 degrees. This
will not fit into a 90 degree increment and will cause
the canvas size to increase.
--->
<cfimage
action="rotate"
source="#objImage#"
angle="225"
name="objImage"
/>
<!--- Write the new image to the browser. --->
<cfimage
action="writetobrowser"
source="#AddImageInfo( objImage )#"
/>
Running the above code, we get the image in Figure 7.
See how the image canvas size had to increase. The background fill color is black. I couldn't figure out how to change this fill color using any of the Image manipulation functions including ImageSetBackgroundColor() and ImageSetDrawingColor(). I'm sure this can be changed, but I just couldn't figure out where to set it.
CFImage - CAPTCHA Creation
CAPTCHA stands for
"Completely Automated Turing Test To Tell Computers and Humans Apart"
and is great for helping to prevent spam bot form submissions. When
using CFImage to create a CAPTCHA graphic, the related attributes (in
addition to the standard CFImage attributes) are:
Verify your inputs. The specified width for the CAPTCHA image is not big enough to fit the text. 363
Here, ColdFusion is telling you that the width is not big enough. What is less clear, but super useful, is that number at the end, 363, is the minimum width that the CAPTCHA image can be.
The text attribute is the text that's displayed in the CAPTCHA image. The point of the CAPTCHA functionality is not to create the text; it is to make it funky. You have to supply the text. Furthermore, there is nothing inherent to the CAPTCHA tag that will submit this text value in a form submission. If you want to use this with form submissions, you have to be sure to submit the text yourself (probably in some encrypted fashion).
The difficulty, which defaults to Low, determines how crazy the CAPTCHA image is.
Fonts is a comma-delimited list of fonts that will be randomly used to render characters within the CAPTCHA image. You can't just use any old font here; according to the documentation, ColdFusion supports only the system fonts that the JD can recognize. For example, TT fonts in the Windows directory are supported on Windows. FontSize, which defaults to 24, determines the size of the characters displayed in the image.
Let's take a look at it in action. I'm going to loop over the different
difficulty levels so you can see how they affect the way the image is
rendered (see Listing 5).
Notice that we are not supplying a destination for the CFImage tag in
this demo. If we leave out that attribute, ColdFusion will display the
CAPTCHA image as an inline image similar to the WriteToBrowser action
for other images. This will create random image names; however, if you
do supply a destination, be very careful to not overwrite images that
might be in use by other users in parallel requests (otherwise, their
image might not correspond to the value that is required).
Running the above code, we get Figures 8, 9, and 10.
That's basically the rundown on how you can use the CFImage tag to manipulate images in ColdFusion 8.
The ColdFusion 8 CFImage tag does some fantastic stuff. But to be honest, it only begins to scratch the surface of what ColdFusion 8 can do in terms of image manipulation. I am trying to keep a good balance here between info and deep exploration in these articles because there is just such a huge wealth of functionality to get through. I hope that seeing the quality and functionality of the CFImage tag will get you excited for more.
This article was reprinted with permission from Ben Nadel's blog: www.bennadel.com/index.cfm?dax=blog:772.view.