Using custom fonts for cfimage in Lucee

In the CFML function imageDrawText() and tag <cfimage action="captcha">, you can enter a font to be used for the text output. Unfortunately, this font must first be available to the JVM (eg. Tomcat) to be able to use it.
I did have the TrueType font file available,  But I did not want to manually add the font file to every Lucee instance. That's not portable code...

Luckily, I found a workaround by programmatically adding the font file to the java.awt.GraphicsEnvironment:

<cfset oFont = createObject('java', 'java.awt.Font') />
<cfset stream = createObject('java', 'java.io.FileInputStream').init(expandPath('./SoftwareFont.ttf')) />
<cfset sFont = oFont.createFont(oFont.TRUETYPE_FONT, stream) />
<cfset createObject('java', 'java.awt.GraphicsEnvironment').getLocalGraphicsEnvironment().registerFont(sFont) />

These 4 lines only have to be executed once during the JVM lifecycle, but it does not throw an error if you execute it multiple times. My suggestion is, to wrap the 4 lines in a conditional statement:

<cfif not structKeyExists(application, "__fontAdded")>
	<cfset oFont = createObject......
	[....]
	<cfset application.__fontAdded = 1 />
</cfif>

To make the example complete, here is a working example implementation:

<!--- download a ttf file --->
<cfset filePath = getTempDirectory() & "Balthazar-Regular.ttf" />
<cfhttp url="https://github.com/google/fonts/blob/master/ofl/balthazar/Balthazar-Regular.ttf?raw=true"
		getasbinary="true" file="#filePath#"/>

<!--- add the font to java.awt.GraphicsEnvironment  --->
​<cfif not structKeyExists(application, "__fontAdded")>
	<cfset oFont = createObject('java', 'java.awt.Font') />
	<cfset stream = createObject('java', 'java.io.FileInputStream').init(filePath) />
	<cfset sFont = oFont.createFont(oFont.TRUETYPE_FONT, stream) />
	<cfset createObject('java', 'java.awt.GraphicsEnvironment').getLocalGraphicsEnvironment().registerFont(sFont) />
	<cfset application.__fontAdded = 1 />
</cfif>

<!--- create an image and write text to it --->
<cfset text = "This IS a custom Font Test with imageDrawText()" />
<cfset myImg = imageNew("", 800, 50) />
<cfset imageSetAntialiasing(myImg, true) />
<cfset imageDrawText(myImg, text, 10, 35, {
	  size="40.0"
	, font="Balthazar"// <<<------ this is what it was all about!
}) />
<cfimage action="write" source="#myImg#" destination="#expandPath('./test1.png')#" quality="1" overwrite="true" />
<!--- output test1 --->
<img src="test1.png" />
<hr/>

<!--- create a captcha file --->
<cfimage action="captcha" text="Captcha test" width="600" height="150" fonts="Balthazar" fontSize="50"
		destination="test2.png" overwrite="true" />
<!--- output test2 --->
<img src="test2.png" />
del.icio.us Digg StumbleUpon Facebook Technorati Fav reddit Google Bookmarks
| Viewed 7063 times
  1. Ben Nadel

    #1 by Ben Nadel - November 10, 2022 at 12:48 PM

    Great thought! I was just trying to figure this out for Adobe ColdFusion 2021; unfortunately, it doesn't seem to work for ACF. I was testing with Roboto. I can get it so that when I call `.getAvailableFontFamilyNames()`, it lists Roboto as an option. However, when I go to use "Roboto" as the font in CFImage, it breaks with the error message, "Unable to find font: Serif."

    Not sure if it's the version of ACF or Java or what, but no luck on my end.
(will not be published)
Leave this field empty