Creating Colors Gradients With ImageUtils.cfc ColdFusion Component

Posted February 19, 2008 at 8:32 AM by Ben Nadel

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:

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

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

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




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 »
11,314 Comments

@Chris,

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


Feb 19, 2008 at 10:17 AM // reply »
8 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 »
11,314 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 »
8 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 »
11,314 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 :)


Oct 7, 2012 at 5:30 AM // reply »
2 Comments

Isn't there a <cfoutput>...</cfoutput> missing in the first part of the code:

<div style="height: 1px ; background-color: rgb( #objColor.Red#, #objColor.Green#, #objColor.Blue# );">

should be

<div style="height: 1px ; background-color: rgb( <cfoutput>#objColor.Red#</cfoutput>, <cfoutput>#objColor.Green#</cfoutput>, <cfoutput>#objColor.Blue#</cfoutput> );">


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 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 »
Jun 19, 2013 at 10:18 AM
ColdFusion Path Usage And Manipulation Overview
Anyone happen to know if the file created by getTempFile will be automatically removed at any point? Nothing mentioned in the docs, and restarting CF doesn't remove them, so it seems it needs manu ... read »
Jun 19, 2013 at 9:41 AM
Working With Inherited Collections In AngularJS
I actually just ran into this same situation with a demo I was putting together. Your implementation of multi-lvl $scope's > Mine :) ... read »
Jun 19, 2013 at 8:17 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
@Prateek, to match a word or text you should use .toContain('word') that's a jasmine reference. website is : http://pivotal.github.io/jasmine/ ... read »
Jun 19, 2013 at 8:10 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
Hi Guys, Actually i am doing e2e test of angular js of my project but i am not getting one thing that is how to press enter key through the test when my form is filled as i am not using a button but ... read »
Jun 18, 2013 at 9:20 PM
Mapping AngularJS Routes Onto URL Parameters And Client-Side Events
I couldn't find examples of passing multiple arguments using the when() routing statement so figured out through trial and error that you can pass multiple arguments using the following format: .whe ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools