Posted February 18, 2008 at
7:00 AM
Tags:
ColdFusion
This weekend, I added two more user defined functions to the ImageUtils.cfc ColdFusion component for image manipulation:
GetPixels() takes a ColdFusion image and returns an array or arrays that contains a structure for each sampled pixel. These structures contain a Red, Green, Blue, Alpha, and Hex key for the Red, Green, Blue, and Alpha channels respectively and the Hex for the 6 digit hexadecimal encoding of the color. By default, if you just pass in the ColdFusion image, GetPixels() will return the pixel data for the entire image. However, you have the option to pass in a starting X and Y coordinate as well as the width and height of the desired sample area:
GetPixels( Image [, X [, Y [, Width [, Height ] ] ] ] ) :: Array
This leverages the underlying Java AWT buffered image object; I am no master of this library, so this might not be the most performant utility function. It will, however, provide me with tools that I will leverage in the authoring of future utility functions.
Let's take a look at an example of how this works. In the demo below, we will take this image:
... and sample a 50px by 50px area in the middle of the image. Then, we will loop over that sample and output it in 3 by 3 divs:
Launch code in new window » Download code as text file »
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html>
- <head>
- <title>GetPixels()</title>
-
- <style type="text/css">
-
- div.canvas {
- background-color: #333333 ;
- border: 1px solid #000000 ;
- float: left ;
- padding: 1px 0px 0px 1px ;
- }
-
- div.row {
- clear: both ;
- height: 3px ;
- margin-bottom: 1px ;
- overflow: hidden ;
- }
-
- div.pixel {
- float: left ;
- font-size: 1px ;
- height: 3px ;
- line-height: 1px ;
- margin: 0px 1px 0px 0px ;
- overflow: hidden ;
- width: 3px ;
- }
-
- </style>
- </head>
- <body>
-
-
- <cfset objImageUtils = CreateObject( "component", "imageutilsroot.imageUtils" ).Init() />
-
- <cfimage
- action="read"
- source="../cute_blonde.jpg"
- name="objImage"
- />
-
- <cfset arrPixels = objImageUtils.GetPixels(
- objImage,
- 200,
- 185,
- 50,
- 50
- ) />
-
-
- <cfoutput>
-
- <div class="canvas">
-
- <cfloop
- index="intY"
- from="1"
- to="#ArrayLen( arrPixels )#"
- step="1">
-
- <div class="row">
-
- <cfloop
- index="intX"
- from="1"
- to="#ArrayLen( arrPixels[ intY ] )#"
- step="1">
-
- <cfset objPixel = arrPixels[ intY ][ intX ] />
-
- <div
- class="pixel"
- style="background-color: ###objPixel.Hex#;"
- ></div>
-
- </cfloop>
-
- </div>
-
- </cfloop>
-
- </div>
-
- </cfoutput>
-
- </body>
- </html>
Running this code, we get the following pixilated output:
As you can see, each pixel is drawn using a 3px by 3px div with an explicit background color using the HEX value returned from the function.
Here is the code behind this functionality:
Launch code in new window » Download code as text file »
- <cffunction
- name="GetPixels"
- access="public"
- returntype="array"
- output="false"
- hint="Returns a two dimensional array of RGBA values for the image. Array will be in the form of Pixels[ Y ][ X ] where Y is along the height axis and X is along the width axis.">
-
- <cfargument
- name="Image"
- type="any"
- required="true"
- hint="The ColdFusion image object whose pixel map we are returning."
- />
-
- <cfargument
- name="X"
- type="numeric"
- required="false"
- default="1"
- hint="The default X point where we will start getting our pixels (will be translated to 0-based system for Java interaction)."
- />
-
- <cfargument
- name="Y"
- type="numeric"
- required="false"
- default="1"
- hint="The default Ypoint where we will start getting our pixels (will be translated to 0-based system for Java interaction)."
- />
-
- <cfargument
- name="Width"
- type="numeric"
- required="false"
- default="#ImageGetWidth( ARGUMENTS.Image )#"
- hint="The width of the area from which we will be sampling pixels."
- />
-
- <cfargument
- name="Height"
- type="numeric"
- required="false"
- default="#ImageGetHeight( ARGUMENTS.Image )#"
- hint="The height of the area from which we will be sampling pixels."
- />
-
- <cfset var LOCAL = {} />
-
- <cfset LOCAL.Pixels = [] />
-
- <cfset LOCAL.Raster = ImageGetBufferedImage( ARGUMENTS.Image ).GetRaster() />
-
-
- <cfloop
- index="LOCAL.Y"
- from="#ARGUMENTS.Y#"
- to="#(ARGUMENTS.Y + ARGUMENTS.Height - 1)#"
- step="1">
-
- <cfset ArrayAppend(
- LOCAL.Pixels,
- ArrayNew( 1 )
- ) />
-
- <cfloop
- index="LOCAL.X"
- from="#ARGUMENTS.X#"
- to="#(ARGUMENTS.X + ARGUMENTS.Width - 1)#"
- step="1">
-
- <cfset LOCAL.PixelArray = JavaCast(
- "int[]",
- ListToArray( "0,0,0,0" )
- ) />
-
- <cfset LOCAL.Raster.GetPixel(
- JavaCast( "int", (LOCAL.X - 1) ),
- JavaCast( "int", (LOCAL.Y - 1) ),
- LOCAL.PixelArray
- ) />
-
- <cfset LOCAL.Pixel = {
- Red = LOCAL.PixelArray[ 1 ],
- Green = LOCAL.PixelArray[ 2 ],
- Blue = LOCAL.PixelArray[ 3 ],
- Alpha = LOCAL.PixelArray[ 4 ],
- Hex = ""
- } />
-
- <cfset LOCAL.Pixel.Hex = UCase(
- Right( "0#FormatBaseN( LOCAL.Pixel.Red, '16' )#", 2 ) &
- Right( "0#FormatBaseN( LOCAL.Pixel.Green, '16' )#", 2 ) &
- Right( "0#FormatBaseN( LOCAL.Pixel.Blue, '16' )#", 2 )
- ) />
-
-
- <cfset ArrayAppend(
- LOCAL.Pixels[ ArrayLen( LOCAL.Pixels ) ],
- LOCAL.Pixel
- ) />
-
- </cfloop>
-
- </cfloop>
-
-
- <cfreturn LOCAL.Pixels />
- </cffunction>
In addition to this function, I also created a GetPixel() function that utilizes the GetPixels() function to return the RGBA values for a single pixel:
Launch code in new window » Download code as text file »
- <cffunction
- name="GetPixel"
- access="public"
- returntype="struct"
- output="false"
- hint="Returns a struct containing the given pixel RGBA data.">
-
- <cfargument
- name="Image"
- type="any"
- required="true"
- hint="The ColdFusion image object whose pixel data map we are returning."
- />
-
- <cfargument
- name="X"
- type="numeric"
- required="true"
- hint="The X coordinate of the pixel that we are returning."
- />
-
- <cfargument
- name="Y"
- type="numeric"
- required="true"
- hint="The Y coordinate of the pixel that we are returning."
- />
-
- <cfset var LOCAL = {} />
-
- <cfset LOCAL.Pixels = GetPixels(
- ARGUMENTS.Image,
- ARGUMENTS.X,
- ARGUMENTS.Y,
- 1,
- 1
- ) />
-
- <cfreturn LOCAL.Pixels[ 1 ][ 1 ] />
- </cffunction>
This returns a single instance of the pixel structure which looks like this:
Download Code Snippet ZIP File
Comments (6) |
Post Comment |
Ask Ben |
Permalink |
Other Searches |
Print Page
What Other People Are Searching For
[ local search ]
getting pixels from image coldfusion
[ local search ]
get rgb value for pixel coldfusion image
[ local search ]
coldfusion image get pixel data
[ local search ]
coldfusion image get color of pixels
That is really cool! (though I can't quite think of a use for it)
Posted by Steve Bryant
on Feb 18, 2008
at 10:44 AM
@Steve,
I actually started coding it with another method in mind. Soon, I will come out with TrimCanvas(). This will remove rows and columns from the edges until it hits "real image content". Basically, this is a way of shrinking a canvas to the smallest possible box without cropped image data.
In FireWorks, this would be CTRL+ALT+T. I figure, I can perform this by sampling pixels until I find one that is not the same as the background color.
Now, not sure if that function will have a use, but I think it will, especially when you do a lot of programmatic pasting of images.
Posted by Ben Nadel
on Feb 18, 2008
at 10:50 AM
*that* is nice! (definitely useful)
So you can get the background color of an image separately?
Can you change the background color for index transparency gifs?
Posted by Steve Bryant
on Feb 18, 2008
at 10:57 AM
@Steve,
I am not sure if you can get the background color of an image since I don't think that is really stored in any capacity once the background is drawn. I might have to end up passing in the background color as a hint:
TrimCanvas( Image, CanvasColor )
As far as working with transparent GIF images, I guess you could create an alpha canvas and then paste the GIF onto that canvas? I am not exactly sure what you are asking.
Posted by Ben Nadel
on Feb 18, 2008
at 11:21 AM
Sorry, my thought only made sense on the assumption that you could have read and write access to a background color property which doesn't seem to be the case.
Still, very nifty. I am eager to see how it comes out.
Posted by Steve Bryant
on Feb 18, 2008
at 11:25 AM
Sweet hack.
Posted by Scott Fitchet
on Mar 11, 2008
at 4:13 PM
Post Comment |
Ask Ben