One of the things that I've been curious about for a while now is if there was a way to determine the graphical size of text when drawing in ColdFusion 8. Why would you need to care about that? While ColdFusion 8 lets you easily draw text on an image, there is no easy way to center it. In order to center it, you need to know the size of the text. Today in CF-TALK this issue came up in a thread.
A user named C S (not sure of his real name) provided the following code which works just dandy:
<cfscript> buffered = ImageGetBufferedImage(theColdFusionImage); context = buffered.getGraphics().getFontRenderContext(); Font = createObject("java", "java.awt.Font"); // font name, style and size textFont = Font.init( "Arial", Font.ITALIC, javacast("int", 15)); textLayout = createObject("java", "java.awt.font.TextLayout").init( text, textFont, context); textBounds = textLayout.getBounds(); dimen.width = textBounds.getWidth(); dimen.height = textBounds.getHeight(); </cfscript><cfdump var="#dimen#">
Ben Nadel then chimed in and pointed out a cool blog entry where he describes how you can take a text string, provide a bounding box, and his UDF will wrap the text correctly within the box. His work was inspired by yet another blog post by Barney Boisvert.
With me so far? ;) So the issue of centering text now becomes simple. When you draw text, the X and Y represent the bottom left corner of the text block. So to center, you simply place the X at: Canvas Width/2 - Text Width/2. Height is the reverse: Canvas Height/2 + Text Height/2.
Here is a complete example. If you change the text, it should re-center accordingly.
<cfset canvas = imageNew("",500,500,"rgb","yellow")> <cfset text = "Paris Hilton kicks butt!"><cfscript> buffered = ImageGetBufferedImage(canvas); context = buffered.getGraphics().getFontRenderContext(); Font = createObject("java", "java.awt.Font"); // font name, style and size textFont = Font.init( "Arial-Black", Font.ITALIC, javacast("int", 15)); textLayout = createObject("java", "java.awt.font.TextLayout").init( text, textFont, context); textBounds = textLayout.getBounds(); dimen.width = textBounds.getWidth(); dimen.height = textBounds.getHeight(); </cfscript>
<cfdump var="#dimen#">
<!--- when drawing text, you specify X, Y as the bottom left corner. So we need to position ourselves at Total Height / 2 + Height of Text / 2 ---> <cfset attr = { font="Arial-Black", size="15", style="italic"}> <cfset newx = (canvas.width/2 - dimen.width/2)> <cfset newy = (canvas.height/2 + dimen.height/2)> <cfset imageSetDrawingColor(canvas,"black")> <cfset imageDrawText(canvas,text, newx, newy, attr)>
<cfimage action="writeToBrowser" source="#canvas#">
There is a reason for all of this that I'll explain later in the week (for my Friday contest probably).
Archived Comments
If anyone is interested, I have been experimenting with a line wrap function that uses java's LineBreakMeasurer. I wrote up an entry on it here
http://cfsearching.blogspot...
Hey Ray.. Has anyone found a way to "smooth out" and anti-alias fonts when adding text to an image? Is there an attribute that I might be missing? I created a dynamic last.fm badge using their audio scrobbler data feed and cfimage but the font leaves a lot to be desired.
See badge at: http://www.last.fm/user/djb...
Dan B,
Are you using the ImageSetAntialiasing function?
http://livedocs.adobe.com/c...
SWEET! Exactly what I was looking for!
Hi ray, ran the same example in CF 9.0.1, and it throws error on Font, Says "Arial-Black" invalid font, i used then another font "Agency FB" and it worked.
Just to bring nto your notice
Cheers
Right, that is to be expected. Different machines will have different fonts available. We actually provide a function so you can check that programatically. (I think it is getAvailableFonts).
Shoot - I stand corrected. I thought we did expose available fonts. Doing some research.
You can use the code here to get the list of fonts dynamically:
http://cfsearching.blogspot...
Thanks Ray!
if i want to place the image just in the bottom middle what constraints i need to change
here is a fubction to list fonts installed
<cffunction name="getFontNames" access="public" returntype="array">
<cfset var allFonts = CreateObject("java", "java.awt.GraphicsEnvironment").getLocalGraphicsEnvironment().getAllFonts() />
<cfset var fontArray = ArrayNew(1) />
<cfset var i = "" />
<cfloop from="1" to="#ArrayLen(allFonts)#" index="i">
<cfset ArrayAppend(fontArray, allFonts[i].getName()) />
</cfloop>
<cfreturn fontArray />
</cffunction>
Please see the imageUtils project at RIAForge. It includes code that lets you "measure" a block of text graphically. This can be used for things like centering.