Now that I have my GraphicsMagick Docker playground up and running, it's time to start recreating some functionality with the
gm command-line tool that I would have historically done with ColdFusion's
CAUTION: I am very much a novice when it comes to GraphicsMagick. As such, please take the following as an exploration, not an explanation.
Going through the GraphicsMagick documentation, I couldn't find anything that really clued-me-in on how to do this. Luckily, I came across a StackOverflow post on how to perform pixel enumeration in ImageMagick. While GraphicsMagick and ImageMagick aren't completely compatible, there's enough overlapping functionality to make ImageMagick posts highly relevant.
From the StackOverflow post, I learned a number of helpful things about GraphicsMagick that come into play in this solution:
GraphicsMagick can write to a
TXTfile format. Using this format triggers "pixel enumeration", wherein GraphicsMagic will iterate over each pixel in the image and write its color-value, in order, to the given file.
:-as part of the destination - as in
txt:-- will cause the result to be written to the standard-out instead of to a physical file. This configuration will allow us to read the results of the
gmoperation in the
variablevalue of our
Given these behaviors, we can get the color value of a given pixel within an image by:
- Reading in the image.
- Cropping it to a 1x1 canvas at the given X,Y offset.
- Writing the 1x1 canvas pixel value to the standard-out using pixel enumeration.
- Parsing the color value from the standard-out.
When GraphicsMagick performs the pixel enumeration, the individual color values look like this:
0,0: ( 0, 79,150, 0) #004F9600 1,0: ( 0, 81,150, 0) #00519600 2,0: ( 1, 83,150, 0) #01539600 3,0: ( 1, 85,150, 0) #01559600 4,0: ( 3, 87,152, 0) #03579800 5,0: ( 2, 89,151, 0) #02599700 6,0: ( 2, 92,152, 0) #025C9800 7,0: ( 2, 93,151, 0) #025D9700 8,0: ( 3, 96,151, 0) #03609700 9,0: ( 4, 99,151, 0) #04639700 0,1: ( 0, 79,152, 0) #004F9800 1,1: ( 0, 81,151, 0) #00519700 2,1: ( 1, 83,151, 0) #01539700 3,1: ( 2, 85,152, 0) #02559800 4,1: ( 3, 88,155, 0) #03589B00 5,1: ( 2, 89,154, 0) #02599A00
This output contains the X/Y offset, the RGBA channels, and the HEX value for each pixel in the resultant image. And, of course, if we crop the image down to a 1x1 canvas, our output will only contain a single line of text. From that text, we can use a Regular Expression pattern (Video presentation) to extract the hexadecimal value.
As you can see, we're using the ColdFusion
CFExecute tag to read in the image file -
palette.png - crop it down to a 1x1 canvas, ensure 8-bit colors, and then write the pixel-enumeration to the standard-out. We then grab the HEX value from our single pixel and use it to color the page's background-color.
And, when I run this page in my Lucee CFML Docker container and click on the image a few times, we get the following output:
It's pretty cool! I will say, however, that the image I am using is fairly small, so this run very quickly. As the image gets larger, however, the speed decreases, presumably because there's more image to read into memory; and then, more image to remove during the crop. I mean, we're still talking sub-second time; but, there's clearly a relationship between the file-size and the speed of this approach.
According to a forum-thread that I found about ImageMagick, it appears that, ImageMagick can combine the file-read with the crop-operation using a special syntax. I tried to do the same thing with GraphicsMagick, but it didn't work. I did create a new thread on SourceForge asking the GraphicsMagick maintainers if there was an equivalent type of syntax for
gm convert. We'll see how that plays-out.
Anyway, this is just me trying to get familiar with the GraphicsMagick command-line tool; and, how I can consume it using
CFExecute in Lucee CFML. If there are easier ways to extract a given color value, please let me know.
Want to use code from this post? Check out the license.
Ben. Interesting stuff!
Even better. You could use an XHR request [Ajax] to get your RGB values. Then you don't need to refresh the page!
This is actually quite powerful stuff. Never even heard of GM/IM. I have always just used CFIMAGE...
Very true! The full-page-refresh in this case was to make things as simple as possible.
At work, we use
new Image() as well. But, we use ImageMagick for some stuff. That said, I've been running into some memory / performance issues with the ColdFusion image functionality. So, I am hoping that I might be able to minimize the memory / CPU footprint if I move to GraphicsMagick for, at least, some of the larger operations. To be fair, I don't actually know if this will have a positive outcome; but, I figure it would at least be fun to play with it a bit.