Using fonts with CFImage

One of the more useful bits of ColdFusion (version 8 and above) is the ability to dynamically write text as an image. As you can imagine, there are nearly endless uses for this. However, one of the more curious things is that it is not that easy to determine which fonts are available for you to use on the system on the fly. You can do it in the Administrative Console, but not programatically. . Worse, if you specify either a non-existent font or one that is not usable, ColdFusion throws a really ugly error. In the Pencilneck CMS, we have a number of bits of code that allow both ourselves & our users to generate images from text on the fly, and so it has become important to know what fonts are available. To that end, I wrote a pair of scripts today that now handle this for me, which I’m going to share below. One important note: In order for this script to work, you must have administrative access to ColdFusion, as it uses one of the Admin API components. The first script simply loads a list of all the valid, usable fontnames in a list (my apologies in advance for this not being properly indented. I’ve not yet found a good way of writing code with WordPress):

<cffunction name=”getServerFonts” access=”public” output=”false” returntype=”string”>
<cfargument name=”loginPW” type=”string” required=”true” />
<cfset var x = structNew() />
<cfscript>
adminObj = createObject(“component”,”cfide.adminapi.administrator”);
// this shoud be the CF admin log in
adminObj.login(arguments.loginPW);
myAdmin = createObject(“component”,”cfide.adminapi.runtime”);
x.fontList = myAdmin.getfonts();
</cfscript>
<cfset x.basicFontList = “” />
<cfloop collection=”#x.fontlist.systemfonts#” item=”x.i”>
<cfloop collection=”#x.fontlist.systemfonts[x.i]#” item=”x.j”>
<!— we disallow the “Adobe Built-in” fonts because CF can’t use them. This list is inclusive, not exclusive simply by my own preference —>
<cfif ListFindNoCase(“TRUETYPE,TRUETYPE-COLLECTION,OPENTYPE”,x.fontlist.systemFonts[x.i][x.j].fonttype)>
<cfset x.basicfontList =ListAppend(x.basicfontList,x.j) />
</cfif>
</cfloop>
</cfloop>

<cfloop collection=”#x.fontlist.userfonts#” item=”x.i”>
<cfloop collection=”#x.fontlist.userfonts[x.i]#” item=”x.j”>
<cfif ListFindNoCase(“TRUETYPE,TRUETYPE-COLLECTION,OPENTYPE”,x.fontlist.userFonts[x.i][x.j].fonttype)>
<cfset x.basicfontList =ListAppend(x.basicfontList,x.j) />
</cfif>
</cfloop>
</cfloop>

<cfreturn listSort(x.basicfontlist,”TextNoCase”) />
</cffunction>

So I like to run this script once on init, and load this list of fonts up into server scope so it’s available to all my applications. Once that exists, it becomes trivial to check for the existence of a font, which I do with the following script:

<cffunction name=”isSystemFont” output=”false” access=”public” returntype=”boolean”>
<cfargument name=”fontName” type=”string” required=”true” />
<cfset var x = structNew() />

<cfif NOT isDefined(‘server.fontList’)>
<!— do this in case the server.fontList hasn’t been initialized yet. If you load your fonts into a different scope, edit this —>
<cfset server.fontlist = getServerFonts() />
</cfif>
<cfif ListFindNoCase(server.fontList,arguments.fontName)>
<cfreturn true />
<cfelse>
<cfreturn false />
</cfif>
</cffunction>

And that’s it. I can now safely test to see if a font is available on a server or not, and then have conditionals by preference, etc. or whatnot. Hopefully, this’ll be useful for you too in your adventures in coding.