Reflecting Images With ImageUtils.cfc ColdFusion Image Component

Posted February 21, 2008 at 8:53 AM

Tags: ColdFusion

I only have a few minutes before I have to do some real work, so I will keep this very brief. This morning, I added the ability to create an image reflection effect, very much like the one that was popularized by Apple and iTunes, and added it to the ImageUtils.cfc ColdFusion image manipulation component:

ReflectImage( Image, Side [, BackgroundColor, Offset, Size, StartingAlpha ] )

Of the listed arguments, the only ones that are required are Image and Side. The rest are individually optional. By default, it assumes you are working on a white background. Here is a quick example of this in action:

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

  • <!--- Read in the cute blonde image (my favorite part). --->
  • <cfimage
  • action="read"
  • source="./cute_blonde.jpg"
  • name="objImage"
  • />
  •  
  • <!--- Create the reflection. Use black background. --->
  • <cfset objImage = ReflectImage(
  • objImage,
  • "Bottom",
  • "##000000"
  • ) />
  •  
  • <!--- Draw image. --->
  • <cfimage
  • action="writetobrowser"
  • source="#objImage#"
  • />

I know this is not the best example, and doesn't even use the ImageUtils.cfc (I am in a crazy hury). Sorry. In this code, we are using a black background override (instead of the white background). The background color must be a HEX value; it will not accept RGB or named colors (at least for the time being). Running the above, we get the following cute blonde output:


 
 
 

 
Cute Blonde Reflected On Black Shiney Surface  
 
 
 

I think that looks pretty slick on a black background.

NOTE: The method does not create the black border around the image. I only included that for a better visual.

As I was building this, I realized that my functions are not consistent on which methods return a NEW image and which methods update the original image. I think that I want to go back and make them all NON-destructive effects. Meaning, I want them to always return a new image and leave the original image unaltered. This way, the ImageUtils.cfc will behave very predictably.

And, very quickly, if you want to see how this function is actually working, here is the code. The actual code that is inside of the ImageUtils.cfc is ever so slightly different, but this gives you the idea:

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

  • <cffunction
  • name="ReflectImage"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="Reflects image along the given side with the given properties.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Image"
  • type="any"
  • required="true"
  • hint="The ColdFusion image object that we are going to reflect."
  • />
  •  
  • <cfargument
  • name="Side"
  • type="string"
  • required="true"
  • hint="The side of the image that we are going to reflect. Valid values include Top, Right, Bottom, and Left."
  • />
  •  
  • <cfargument
  • name="BackgroundColor"
  • type="string"
  • required="false"
  • default="FFFFFF"
  • hint="The HEX color of the canvas background color used in the reflection."
  • />
  •  
  • <cfargument
  • name="Offset"
  • type="numeric"
  • required="false"
  • default="0"
  • hint="The offset of the reflection from the image."
  • />
  •  
  • <cfargument
  • name="Size"
  • type="numeric"
  • required="false"
  • default="100"
  • hint="The height or width of the given reflection (depending on the side being reflected)."
  • />
  •  
  • <cfargument
  • name="StartingAlpha"
  • type="numeric"
  • required="false"
  • default="25"
  • hint="The starting alpha channel of the covering !!background color!! (between 0 and 255 where 0 is completely transparent)."
  • />
  •  
  • <!--- Set up local scope. --->
  • <cfset var LOCAL = {} />
  •  
  •  
  • <!--- Check to make sure that we have a valid side. --->
  • <cfif NOT ListFindNoCase( "Top,Right,Bottom,Left", ARGUMENTS.Side )>
  •  
  • <!---
  • An invalid side was passed in, so just default
  • to the most popular: bottom.
  • --->
  • <cfset ARGUMENTS.Side = "Bottom" />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Before we apply the reflection, we have to figure
  • out what the size of our resulting canvas will be.
  • This is going to be different depending on what side
  • we are refelcting.
  • --->
  • <cfif ListFindNoCase( "Top,Bottom", ARGUMENTS.Side )>
  •  
  • <!--- We are reflecting in the vertical plane. --->
  •  
  • <!---
  • Get the size of the resultant canvas. This will be
  • the same width, but will need to take into account
  • the size and offset of the reflection.
  • --->
  • <cfset LOCAL.Width = ImageGetWidth( ARGUMENTS.Image ) />
  •  
  • <cfset LOCAL.Height = (
  • ImageGetHeight( ARGUMENTS.Image ) +
  • ARGUMENTS.Offset +
  • ARGUMENTS.Size
  • ) />
  •  
  • <cfelse>
  •  
  • <!--- We are reflecting in the horizontal plane. --->
  •  
  • <!---
  • Get the size of the resultant canvas. This will be
  • the same height, but will need to take into account
  • the size and offset of the reflection.
  • --->
  • <cfset LOCAL.Height = ImageGetHeight( ARGUMENTS.Image ) />
  •  
  • <cfset LOCAL.Width = (
  • ImageGetWidth( ARGUMENTS.Image ) +
  • ARGUMENTS.Offset +
  • ARGUMENTS.Size
  • ) />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Create the new canvas with the above calculated
  • dimensions. Leave the background transparent in
  • case the user wants to use the reflection over
  • something else.
  • --->
  • <cfset LOCAL.Result = ImageNew(
  • "",
  • LOCAL.Width,
  • LOCAL.Height,
  • "argb"
  • ) />
  •  
  •  
  • <!---
  • Create a copy of the passed in image. We are going
  • to be building our reflection gradient over this image.
  • --->
  • <cfset LOCAL.Reflection = ImageCopy(
  • ARGUMENTS.Image,
  • 0,
  • 0,
  • ImageGetWidth( ARGUMENTS.Image ),
  • ImageGetHeight( ARGUMENTS.Image )
  • ) />
  •  
  • <!---
  • Now, we actually need to flip the image that we are
  • going to reflect. This will be either veritcal or
  • horizontal depending on the side.
  • --->
  • <cfif ListFindNoCase( "Top,Bottom", ARGUMENTS.Side )>
  •  
  • <!--- Flip vertical. --->
  • <cfset ImageFlip( LOCAL.Reflection, "vertical" ) />
  •  
  • <cfelse>
  •  
  • <!--- Flip horizontal. --->
  • <cfset ImageFlip( LOCAL.Reflection, "horizontal" ) />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Get the colors that will be used in the gradient.
  • These will both be the same color, but with different
  • alpha channels.
  • --->
  • <cfset LOCAL.FromColor = HexToRGB( ARGUMENTS.BackgroundColor ) />
  • <cfset LOCAL.ToColor = StructCopy( LOCAL.FromColor ) />
  •  
  • <!---
  • The from color will have the given starting alpha and
  • the to color will always have an alpha of 255 which will
  • give us a solid background.
  • --->
  • <cfset LOCAL.FromColor.Alpha = ARGUMENTS.StartingAlpha />
  • <cfset LOCAL.ToColor.Alpha = 255 />
  •  
  •  
  • <!---
  • Now that we have our reflection image, we have to figure
  • out how we want to build the fade-to-background color
  • gradient. This is going to be dependent on what side is
  • being reflected.
  •  
  • Once we have that, let's create the new image by pasting
  • both the original image and the reflection image onto
  • the new canvas.
  • --->
  • <cfswitch expression="#ARGUMENTS.Side#">
  •  
  • <cfcase value="Top">
  •  
  • <!--- Create reflection w/ Gradient. --->
  • <cfset LOCAL.Reflection = DrawGradientRect(
  • LOCAL.Reflection,
  • 0,
  • (ImageGetHeight( LOCAL.Reflection ) - ARGUMENTS.Size),
  • ImageGetWidth( LOCAL.Reflection ),
  • ARGUMENTS.Size,
  • LOCAL.FromColor,
  • LOCAL.ToColor,
  • "BottomTop"
  • ) />
  •  
  • <!--- Paste original object onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • ARGUMENTS.Image,
  • 0,
  • (ImageGetHeight( LOCAL.Result ) - ImageGetHeight( ARGUMENTS.Image ))
  • ) />
  •  
  • <!--- Paste reflection onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • LOCAL.Reflection,
  • 0,
  • (-ImageGetHeight( LOCAL.Reflection ) + ARGUMENTS.Size)
  • ) />
  •  
  • </cfcase>
  •  
  • <cfcase value="Bottom">
  •  
  • <!--- Create reflection w/ Gradient. --->
  • <cfset LOCAL.Reflection = DrawGradientRect(
  • LOCAL.Reflection,
  • 0,
  • 0,
  • ImageGetWidth( LOCAL.Reflection ),
  • ARGUMENTS.Size,
  • LOCAL.FromColor,
  • LOCAL.ToColor,
  • "TopBottom"
  • ) />
  •  
  • <!--- Paste original object onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • ARGUMENTS.Image,
  • 0,
  • 0
  • ) />
  •  
  • <!--- Paste reflection onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • LOCAL.Reflection,
  • 0,
  • (ImageGetHeight( ARGUMENTS.Image ) + ARGUMENTS.Offset)
  • ) />
  •  
  • </cfcase>
  •  
  • <cfcase value="Left">
  •  
  • <!--- Create reflection w/ Gradient. --->
  • <cfset LOCAL.Reflection = DrawGradientRect(
  • LOCAL.Reflection,
  • (ImageGetWidth( LOCAL.Reflection ) - ARGUMENTS.Size),
  • 0,
  • ARGUMENTS.Size,
  • ImageGetHeight( LOCAL.Reflection ),
  • LOCAL.FromColor,
  • LOCAL.ToColor,
  • "RightLeft"
  • ) />
  •  
  • <!--- Paste original object onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • ARGUMENTS.Image,
  • (ImageGetWidth( LOCAL.Result ) - ImageGetWidth( ARGUMENTS.Image )),
  • 0
  • ) />
  •  
  • <!--- Paste reflection onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • LOCAL.Reflection,
  • (-ImageGetWidth( LOCAL.Reflection ) + ARGUMENTS.Size),
  • 0
  • ) />
  •  
  • </cfcase>
  •  
  • <cfcase value="Right">
  •  
  • <!--- Create reflection w/ Gradient. --->
  • <cfset LOCAL.Reflection = DrawGradientRect(
  • LOCAL.Reflection,
  • 0,
  • 0,
  • ARGUMENTS.Size,
  • ImageGetHeight( LOCAL.Reflection ),
  • LOCAL.FromColor,
  • LOCAL.ToColor,
  • "LeftRight"
  • ) />
  •  
  • <!--- Paste original object onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • ARGUMENTS.Image,
  • 0,
  • 0
  • ) />
  •  
  • <!--- Paste reflection onto canvas. --->
  • <cfset ImagePaste(
  • LOCAL.Result,
  • LOCAL.Reflection,
  • (ImageGetWidth( ARGUMENTS.Image ) + ARGUMENTS.Offset),
  • 0
  • ) />
  •  
  • </cfcase>
  •  
  • </cfswitch>
  •  
  •  
  • <!---
  • We have created the reflection. Now, return the
  • resulting canvas.
  • --->
  • <cfreturn LOCAL.Result />
  • </cffunction>

Download Code Snippet ZIP File

Comments (6)  |  Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Adobe ColdFusion 8.0.1 Update - Helping Programmers To Be Signifanctly Less Girlie - Download ColdFusion 8 Update 8.0.1 Now.

Reader Comments

Heh and to think a certain someone charges $39.99 for developing this solution. I think you just put them out of business dude. ;)

Posted by Todd Rafferty on Feb 21, 2008 at 9:27 AM


To be clear, Todd, it wasn't my, or Ben's, intention to put anyone out of business. As a 'personal' project, there is only so much we can do on the support side versus a commercial company. That right there gives a commercial product an advantage over our solution.

Posted by Raymond Camden on Feb 21, 2008 at 9:51 AM


True. Nor am I worried about anyone being put out of business. It was a teasing jab.

Posted by Todd Rafferty on Feb 21, 2008 at 9:59 AM


Heh ok, just being sure. I know that I've been accused of this in the past, so I may be a little bit sensitive. :)

Posted by Raymond Camden on Feb 21, 2008 at 10:01 AM


We just like building cool stuff :)

Posted by Ben Nadel on Feb 21, 2008 at 10:04 AM


Yup, me too.

I have a stupid ajaxproxy issue that I'm racking my head on if any of you want to peek at it and point out what I'm doing wrong. I saw code elsewhere that says it should be working, but my code says it's not. :(

Posted by Todd Rafferty on Feb 21, 2008 at 10:07 AM


Post Comment  |  Ask Ben


Home   |   Web Log   |   ColdFusion   |   Projects   |   Resume   |   Job Form   |   Search   |   Contact
Epicenter Consulting - Custom Software Solutions for Business Evolution HostMySite.com - The Leader In ColdFusion Hosting