Creating Colors Gradients With ImageUtils.cfc ColdFusion Component

Posted February 19, 2008 at 8:32 AM

Tags: ColdFusion

This morning, I updated the ImageUtils.cfc image manipulation component for ColdFusion 8. I gave it the ability to create gradients; well, not really create them just yet, but rather to calculate them. Creating them in rectangles will probably come in the next update. Right now, you can use the CalculateGradient() method to find all the color steps (including the alpha channel) between a From color and a To color over a given number of steps. To demonstrate this, let's calculate the color gradient between black and dark blue and then output each of those color steps in an HTML Div:

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

  • <!---
  • Transition from black to meidum blue. In order to do this,
  • we are going to need to get the RGB values for each hex
  • color value.
  • --->
  • <cfset objFromColor = HexToRGB( "##000000" ) />
  • <cfset objToColor = HexToRGB( "##3300CC" ) />
  •  
  • <!---
  • Calculate color gradient based on 400 steps. This will
  • return an array of length 400 in which each index holds the
  • given color of that step of the gradient.
  • --->
  • <cfset arrGradient = CalculateGradient(
  • objFromColor,
  • objToColor,
  • 400
  • ) />
  •  
  • <!--- Loop over the color steps in the gradient. --->
  • <cfloop
  • index="objColor"
  • array="#arrGradient#">
  •  
  • <div style="height: 1px ; background-color: rgb( #objColor.Red#, #objColor.Green#, #objColor.Blue# );">
  • <br />
  • </div>
  •  
  • </cfloop>

As you can see, we get the array of color gradient steps. Then, we loop over that array and output a Div with the given RGB background color of the given current gradient step. Running this code, we get the following HTML output:


 
 
 

 
Black To Blue Gradient Created Using ImageUtils.cfc  
 
 
 

Now, in order to do this, we are using two functions (both of which have been added to the ImageUtils.cfc). The first is HexToRGB(). This function simply takes your 6 digit HEX color value and returns a struct that contains a Red, Green, and Blue key with the equivalent decimal values for the different color channels. This is just going to be a utility function that is used by other methods of the ImageUtils.cfc (I probably have to go back and factor this into some other methods). This method is really small:

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

  • <cffunction
  • name="HexToRGB"
  • access="public"
  • returntype="struct"
  • output="false"
  • hint="Takes a 6 digit hex value and returns a struct with Red, Green, and Blue keys.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Hex"
  • type="string"
  • required="true"
  • hint="The 6 digit hex color value."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = {} />
  •  
  • <!--- Remove any non-hex values. --->
  • <cfset ARGUMENTS.Hex = REReplace(
  • ARGUMENTS.Hex,
  • "(?i)[^0-9A-F]+",
  • "",
  • "all"
  • ) />
  •  
  • <!--- Get the decimal value of this hex. --->
  • <cfset LOCAL.DecimalColor = InputBaseN( ARGUMENTS.Hex, "16" ) />
  •  
  • <!--- Create the RGB struct. --->
  • <cfset LOCAL.Return = {
  • Red = BitSHRN(
  • BitAnd( LOCAL.DecimalColor, InputBaseN( "FF0000", 16 ) ),
  • 16
  • ),
  • Green = BitSHRN(
  • BitAnd( LOCAL.DecimalColor, InputBaseN( "00FF00", 16 ) ),
  • 8
  • ),
  • Blue = BitAnd( LOCAL.DecimalColor, InputBaseN( "0000FF", 16 ) )
  • } />
  •  
  • <!--- Return RGB color. --->
  • <cfreturn LOCAL.Return />
  • </cffunction>

Then, the primary method for this example is the CalculateGradient() method. This takes the From color in RGBA struct format, the To color also in RGBA struct format, and the number of steps over which to create the gradient. Right now, the gradient is a linear gradient; perhaps in the future, there will be more of an "easing" gradient available. In order to make this utility function as reusable as possible, is simply calculates the color at each step of the gradient and returns an array containing every single one of those colors (one color/step per array index). This way, the gradient calculation can be used by many other methods that require gradient work.

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

  • <cffunction
  • name="CalculateGradient"
  • access="public"
  • returntype="array"
  • output="false"
  • hint="Given a From and To structure that contain Red, Green, Blue, and Alpha keys, it will return the equivalent structs for each step of the gradient.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="FromColor"
  • type="struct"
  • required="true"
  • hint="A struct containing Red, Green, Blue and an optoinal Alpha key (alpha defaults to 255 if not included)."
  • />
  •  
  • <cfargument
  • name="ToColor"
  • type="struct"
  • required="true"
  • hint="A struct containing Red, Green, Blue and an optoinal Alpha key (alpha defaults to 255 if not included)."
  • />
  •  
  • <cfargument
  • name="Steps"
  • type="numeric"
  • required="true"
  • hint="The number of steps overwhich to calculate the gradient."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = {} />
  •  
  •  
  • <!--- Param the alpha values. --->
  • <cfparam
  • name="ARGUMENTS.FromColor.Alpha"
  • type="numeric"
  • default="255"
  • />
  •  
  • <cfparam
  • name="ARGUMENTS.ToColor.Alpha"
  • type="numeric"
  • default="255"
  • />
  •  
  •  
  • <!---
  • Find the differences between the two and from colors.
  • We will getting this by finding the difference of each
  • color chanel in RGB format.
  • --->
  • <cfset LOCAL.RedDelta = (ARGUMENTS.ToColor.Red - ARGUMENTS.FromColor.Red) />
  • <cfset LOCAL.GreenDelta = (ARGUMENTS.ToColor.Green - ARGUMENTS.FromColor.Green) />
  • <cfset LOCAL.BlueDelta = (ARGUMENTS.ToColor.Blue - ARGUMENTS.FromColor.Blue) />
  • <cfset LOCAL.AlphaDelta = (ARGUMENTS.ToColor.Alpha - ARGUMENTS.FromColor.Alpha) />
  •  
  • <!---
  • Based on the number of steps that we want to define the
  • gradient, find the step for each color delta.
  • --->
  • <cfset LOCAL.RedStep = (LOCAL.RedDelta / ARGUMENTS.Steps) />
  • <cfset LOCAL.GreenStep = (LOCAL.GreenDelta / ARGUMENTS.Steps) />
  • <cfset LOCAL.BlueStep = (LOCAL.BlueDelta / ARGUMENTS.Steps) />
  • <cfset LOCAL.AlphaStep = (LOCAL.AlphaDelta / ARGUMENTS.Steps) />
  •  
  •  
  • <!--- Create an array to hold the color steps. --->
  • <cfset LOCAL.Gradient = [] />
  •  
  • <!--- Create a start color. --->
  • <cfset LOCAL.Color = StructCopy( ARGUMENTS.FromColor ) />
  •  
  • <!--- Loop over color differences to calculate. --->
  • <cfloop
  • index="LOCAL.StepIndex"
  • from="1"
  • to="#ARGUMENTS.Steps#"
  • step="1">
  •  
  • <!--- Store the gradient step. --->
  • <cfset ArrayAppend(
  • LOCAL.Gradient,
  • StructCopy( LOCAL.Color )
  • ) />
  •  
  • <!---
  • Increment color. In order to make sure that the
  • gradient steps get used appropriatly, add the steps
  • directly the FROM color rather than to the previous
  • color index. This will prevent the Fix() function
  • from stopping our gradient if the increment is too
  • small.
  • --->
  • <cfset LOCAL.Color.Red = Fix( ARGUMENTS.FromColor.Red + (LOCAL.RedStep * LOCAL.StepIndex) ) />
  • <cfset LOCAL.Color.Green = Fix( ARGUMENTS.FromColor.Green + (LOCAL.GreenStep * LOCAL.StepIndex) ) />
  • <cfset LOCAL.Color.Blue = Fix( ARGUMENTS.FromColor.Blue + (LOCAL.BlueStep * LOCAL.StepIndex) ) />
  • <cfset LOCAL.Color.Alpha = Fix( ARGUMENTS.FromColor.Alpha + (LOCAL.AlphaStep * LOCAL.StepIndex) ) />
  •  
  • </cfloop>
  •  
  •  
  • <!--- Return gradient array. --->
  • <cfreturn LOCAL.Gradient />
  • </cffunction>

Right now, I am concentrating on laying a foundation of small utility functions. Once we get a good base of these, we can start to make some more complex functions.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page




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

Reader Comments

Feb 19, 2008 at 9:48 AM // reply »
9 Comments

Ben,

As always, great work!


Feb 19, 2008 at 10:00 AM // reply »
7,539 Comments

@Chris,

Thanks man. I think we are gonna get some cool stuff going here.


Feb 19, 2008 at 10:17 AM // reply »
7 Comments

Ben, notice the subtle jumps in gradient you get at certain steps. I wonder if you would get an even smoother gradient if you converted RGB to HSV and did all the work there? From what I've done in the past, I don't think it was possible to do a straight Hex-HSV conversion, but had to go through RGB first.


Feb 19, 2008 at 10:24 AM // reply »
7,539 Comments

@Duncan,

I definitely notices the gradient steps. However, my monitor doesn't really handle gradients very well for display. I tried creating a gradient in FireWorks and noticed that it had those same steps in the program. As such, I figured that was just the best I could do.

What is this HSV you are talking about? I am not familiar with this?


Feb 19, 2008 at 1:39 PM // reply »
7 Comments

Hue, Saturation and Value. I did some work on colour gradients not too long ago (automatically working out different menu colours for dynamically nested menus), and I did it using HSV instead of RGB. So I knew I was going from say light red to dark red, which is very easy to do in HSV. At least I think that was the reasoning...


Feb 19, 2008 at 1:42 PM // reply »
7,539 Comments

@Duncan,

Sounds interesting. I will take a look into it. But, the key things here is that since this method encapsulates the gradient calculation, I can definitely swap it out later and not worry about what other parts of the code reference it :)


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 18, 2010 at 4:04 PM
jQuery's Event Triggering, Order Of Default Behavior, And triggerHandler()
Tks! You saved-me today. it can be chained into one statement: $("#x).attr("checked","checked").triggerHandler('click'); ... read »
Mar 18, 2010 at 1:18 PM
Finally Finished Ayn Rand's Atlas Shrugged Audio Book
@joaopft, Not disputing what you say - but... If I understand you correctly, you are saying that Positivism is based on sense experience (what I experience is what is), but Quantum theory states tha ... read »
Mar 18, 2010 at 11:48 AM
Duplicate() Much Faster Than ColdFusion Query-of-Queries
I am working on a massive xml parsing, qofq app to create 2 seperate xml files. I just don't understand the concept/purpose of duplicate function, are you duplicating the data or the row, into a new ... read »
Mar 18, 2010 at 11:22 AM
Exploring ColdFusion Component Runtime Class Properties And Serialization
@Zarko, Ha ha, you know ColdFusion is my first love ;) ... read »
Mar 18, 2010 at 11:15 AM
Exploring ColdFusion Component Runtime Class Properties And Serialization
Hi Ben, nice to have you back! I already gave up on you, thinking you'll write about jQuery and iPhone for the rest our our lives! :) ... read »
Mar 18, 2010 at 10:36 AM
Ask Ben: Javascript Replace And Multiple Lines / Line Breaks
@Ben Nadel, Hey Ben, thanks for you're response. It works!! However.. if you could please kindly look at http://edeals.zzl.org/divchange2.php where I am trying it out you will see that with the " ... read »
Mar 18, 2010 at 9:56 AM
SQL COUNT( NULLIF( .. ) ) Is Totally Awesome
This works too. I learned this trick a long time ago and it's really powerful for flags. SELECT g.hair , COUNT(*) AS girl_count , sum(did_date) AS did_date_count , sum(abs(did_date - 1)) AS did_ ... read »
Mar 18, 2010 at 9:16 AM
Using A SQL JOIN In A SQL DELETE Statement (Thanks Pinal Dave!)
Forget the last part of that. Wasn't thinking straight and hadn't done it exactly that way myself. It'll work if you're doing an 'In' but if you're doing a 'Not In' as above it'll do each check acr ... read »