Wednesday, January 16, 2008

Measuring image text width and height using ColdFusion 8 (Follow up)

In the entry Measuring image text width and height using ColdFusion 8 I talked about two methods for measuring the width and height of text string drawn on an image. But I never got around to posting the function I was working on last night!

Before I do, I wanted to mention one gotcha I discovered about images and default font information. Font properties supplied to the ImageDrawText function are optional. If you omit one of the attributes like style or size, ColdFusion simply uses default values instead. As you will see in the function below, you can use the graphics of an image to obtain the default font information. With one exception: the size. The ColdFusion documentation indicates it uses a default font size of 10 points. On my system the default font size in java is 12. So you must override the default font size or you may get the wrong results when a size is not specified.


UPDATE: After running some checks on the Fonts, I am not convinced the default font size is 10 points. So I have updated the code to use the java defaults instead.


Example

<!--- create the image --->
<cfset img = ImageNew("", 300, 80, "rgb", "lightgray")>
<!--- get the text dimensions --->
<cfset prop = { font="Times New Roman", style="bolditalic", size=18}>
<cfset dimen = ImageGetTextDimensions(img, "Draw this! ÀÇŸÍÊÃ", prop)>
<!--- draw the text --->
<cfset ImageSetAntiAliasing(img, "on")>
<cfset ImageSetDrawingColor(img, "black")>
<cfset ImageDrawText(img, "Draw this! ÀÇŸÍÊÃ", 15, 55, prop)>

<!--- display the image and dimensions--->
<cfimage action="writeToBrowser" source="#img#">
<cfdump var="#dimen#">


Function Code

<cffunction name="ImageGetTextDimensions" returntype="struct" access="public" output="false">
<cfargument name="image" type="any" required="true">
<cfargument name="text" type="string" required="true">
<cfargument name="fontAttributes" type="any" required="false" default="#structNew()#">

<cfset var Local = structNew()>

<cfscript>
// create a reusable font object
Local.Font = createObject("java", "java.awt.Font");
Local.DefaultFont = Local.Font.init( javacast("null", "") );

// determine if any font attributes were supplied
Local.fontPropertiesFound = structKeyExists(arguments, "fontAttributes");

// extract the supplied font name
if (Local.fontPropertiesFound AND structKeyExists(arguments.fontAttributes, "font") ) {
Local.text.font = arguments.fontAttributes.font;
}
else {
// if no font was given, get default system font from the graphics object
Local.text.font = Local.DefaultFont.getName();
}

// extract the font size
if (Local.fontPropertiesFound AND structKeyExists(arguments.fontAttributes, "size") ) {
Local.text.size = arguments.fontAttributes.size;
}
else {
Local.text.size = Local.DefaultFont.getSize();
}

// extract the font style
if (Local.fontPropertiesFound AND structKeyExists(arguments.fontAttributes, "style") ) {
switch (arguments.fontAttributes.style) {
case "bold":
Local.text.style = Local.Font.BOLD;
break;
case "italic":
Local.text.style = Local.Font.ITALIC;
break;
case "bolditalic":
Local.text.style = BitOr( Local.Font.BOLD, Local.Font.ITALIC);
break;
case "plain":
Local.text.style = Local.Font.PLAIN;
break;
}
}
else {
// if no style was given, use the default "plain" (per CF8 documentation)
Local.text.style = Local.DefaultFont.getStyle();
}

// create a font for drawing the text
Local.textFont = Local.Font.init( javacast("string", Local.text.font),
javacast("int", Local.text.style),
javacast("int", Local.text.size)
);

// extract the graphics from the underlying buffered image
Local.graphics = ImageGetBufferedImage(arguments.image).getGraphics();

// get the renderer context for measuring the text
Local.context = Local.graphics.getFontRenderContext();

// use a TextLayout to obtain the graphical representation of the text
Local.textLayout = createObject("java", "java.awt.font.TextLayout").init(
javacast("string", arguments.text),
Local.textFont,
Local.context
);

// get the text bounds
Local.textBounds = Local.textLayout.getBounds();

// save the text dimensions
Local.dimensions.width = Local.textBounds.getWidth();
Local.dimensions.height = Local.textBounds.getHeight();
Local.dimensions.leading = Local.textlayout.getLeading();
Local.dimensions.ascent = Local.textlayout.getAscent();
Local.dimensions.descent = Local.textlayout.getDescent();
Local.dimensions.advance = Local.textlayout.getAdvance();
Local.dimensions.visibleAdvance = Local.textlayout.getVisibleAdvance();

Local.graphics.dispose();
</cfscript>

<cfreturn Local.dimensions >
</cffunction>

0 comments:

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep