Friday, July 4, 2008

What Fonts are Available in myJVM?

A while back I was looking for a quick way to determine what fonts were available in my JVM. I came across the java GraphicsEnvironment class, which returns an array of font families available in the current graphics environment. So I threw together a quick loop, and presto .. I had sample images of the available fonts in my JVM.


<cfset environ = createObject("java", "java.awt.GraphicsEnvironment").getLocalGraphicsEnvironment()>
<cfset allFamilies = environ.getAvailableFontFamilyNames()>

<h3>Display Available Font Families</h3>

<table>
<cfoutput>
<cfset failedFonts = [] >
<cfloop array="#allFamilies#" index="family">
<cftry>
<cfset img = ImageNew("", 200, 35, "argb", "##dcdcdc")>
<cfset prop = { font=family, size="14", style="plain" }>
<cfset ImageSetAntiAliasing( img, "on" )>
<cfset ImageSetDrawingColor( img, "##000000" )>
<cfset ImageDrawText( img, family, 15, 15, prop)>
<cfset wasRendered = true>

<cfcatch>
<cfset arrayAppend( failedFonts, family )>
<cfset wasRendered = false>
</cfcatch>
</cftry>

<cfif wasRendered>
<tr><td><cfimage action="writeToBrowser" source="#img#"></td></tr>
</cfif>
</cfloop>
</cfoutput>
</table>
<br>

<h3>Unable to display fonts:</h3>
<cfdump var="#failedFonts#">




One thing that surprised me was that a few of the fonts could not be displayed. Namely the five (5) logical fonts and a few of the Lucida fonts. If you are not familiar with the term logical fonts, one of the old sun api's describes them as:


" .. not actual font libraries that are installed anywhere on your system. They are merely font-type names recognized by the Java runtime which must be mapped to some physical font that is installed on your system."


While I understand the difference between logical and physical fonts, I was still surprised logical font names were not accepted by the ImageDrawText function. When I created a java Font object directly, it worked fine. So I guess I was expecting ImageDrawText to behave the same way.

Using Java Font Object

<cfscript>
img = ImageNew("", 100, 50, "argb");
Color = createObject("java", "java.awt.Color");
Font = createObject("java", "java.awt.Font");
textFont = Font.init( "Dialog", Font.PLAIN, javacast("int", 12));
graphics = ImageGetBufferedImage( img ).getGraphics();
graphics.setColor( Color.BLACK );
graphics.setFont( textFont );
graphics.drawString( textFont.getFamily(), javacast("int", 10), javacast("int", 10) );
</cfscript>

<cfimage action="writeToBrowser" source="#img#">


As the documentation on ImageDrawText does not say much about the "font" attribute, that may be a misunderstanding on my part. If anyone can shed some light on this, I am eager to be enlightened ;-)

5 comments:

jwhite1202 July 14, 2009 at 7:31 AM  

Hey,

I saw this trying to find a solution to an issue we are having trying add fonts to our CF Server. I wanted to know if you ever had any problems adding Fonts to a CF 8 server where you see a java stack error similar to this:

java.lang.NoSuchMethodError: com.lowagie.text.FontFactory.getFontProperties()Ljava/util/Map;

at coldfusion.document.DocumentServiceImpl.isFontPathRegistered(DocumentServiceImpl.java:698)

at coldfusion.document.DocumentServiceImpl._registerFontFile(DocumentServiceImpl.java:296)

at coldfusion.document.DocumentServiceImpl.registerFontDirectory(DocumentServiceImpl.java:367)


That's not the whole stack, just the first few lines to give you an idea. We know we need to add more fonts, but CF Admin keeps returning the above error when we try. Any suggestions?

cfSearching July 14, 2009 at 9:38 AM  

@JW,

I have not seen that error using the _Administrator_. It is a bit odd. If you use createObject to create a FontFactory reference, then dump it, that method definitely exists.

Are there multiple versions of iText in your classpath for some reason? Or is there anything unusual about the fonts you are trying to add?

-Leigh

jwhite1202 July 14, 2009 at 9:48 AM  

Not that I know of, and the weird thing it is, the issue does not persist across all the servers. In fact, i was able to do it on my local machine and 3 of the 6 servers we use do not have the issue. My boss however, does see the issue on the dev box. Go figure

cfSearching July 14, 2009 at 10:04 AM  

@JW,

Very odd. Maybe the error is just masking some other problem or exception further down in the trace?

Though it is probably not the issue, you might run a quick check just to rule out the usual causes of methodnotfound errors:

a) Verify you can create that class via createObject(...)
b) Dump it and verify that method exists
c) Verify it was created from the standard {cf8root}\lib jar:

Which jar file a class was loaded from

jwhite1202 July 14, 2009 at 10:34 AM  

I'll give it a try and see what I find. Thx.

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep