I am attempting to create a java.awt.Font instance from a TTF file on my system, but only some fonts are able to load without error. The code below is some test code I found online. When run on my system, it is able to load 285 fonts successfully (ex. Arial.ttf), but fails on 83 fonts, (ex. AmericanTypewriter.ttf).
All errors are of the form FontFormatException: Font name not found
with no embedded cause.
Are there known issues with java.awt.Font and format compatibility? I can't find anything after much Googling.
public static void main(String[] args) {
String rootPath = "/Library/Fonts";
File root = new File(rootPath);
if (root.canRead()) {
String[] fontFiles = root.list();
Font font = null;
for (String fontFile : fontFiles) {
try {
System.out.println(fontFile);
font = Font.createFont(Font.TRUETYPE_FONT, new File(root + "/" + fontFile));
System.out.println(font);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
My environment is Java 7, OS X Mavericks (10.9.1).
java version "1.7.0_40"
Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)
Any help here would be greatly appreciated.
OK, so after some digging, it turns out that this problem is due to a bug (feature!) in the java.awt implementation. Namely, loading a physical TrueType font fails if the font file's name table does not include family name and full name records.
To identify the problem, I used GrepCode to trace backward from the relevant exception in OpenJDK's AWT implementation. Once I had discovered the name table issue, I used ttx, a no-frills TrueType metadata editor to add the name entries Java looks for. Ex:
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
American Typewriter
</namerecord>
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
American Typewriter
</namerecord>
The new TTF files generated by ttx could now be opened by Java. Yay!
This is an Oracle JDK/OpenJDK feature (bug).
The problem is caused by sun.font.TrueTypeFont
and its lack of support for Mac TrueType font names.
TrueTypeFont.java
contains a check for reading the name table of a TrueType font to only read the Microsoft platform ID name (platformID == 3)
and not the Mac platform ID (platformID == 1)
. In many cases, truetype fonts included on OSX only have names with a platformID
of 1. Because of this, the initNames()
method does not set a value for either familyName
or fullName
and the code after initNames()
runs checks to see if they are null (which they are of course) and throws the Font name not found
exception.
On Apple JDK (1.6 and maybe 1.5?), Apple didn't use TrueTypeFont as the FontHandler. They had their own implementation which is called sun.font.AppleNativeFont
. You can't even use sun.font.TrueTypeFont
on Apple JDK because it will always use the sun.font.AppleNativeFont
handler, which has support for both Mac and Microsoft platform IDs.
It appears that sun.font.AppleNativeFont
doesn't exist in OpenJDK or Oracle JDK, even though Apple "donated" the code to Oracle.
It would be handy from a continuity point of view to include sun.font.AppleNativeFont
in OpenJDK/Oracle JDK. It would be even better if TrueTypeFont.java
was improved to include support for Mac TrueType fonts.
UPDATE: WORKAROUND SOLUTION.
One of the patches in the comments below was submitted to the OpenJDK repository. If you clone the repository with the right revision, you can get the patched files.
hg clone -r 8b05f9b91765 http://hg.openjdk.java.net/jdk7/jdk7/jdk
Copy these following files from jdk/src/shared/classes/sun/font
:
TrueTypeFont.java
LCIDMap.java
AppleLangID.java
To the same directory in the trunk of a current JDK (I used jdk8-b132), compile it and you will have Mac font support. You may also want to apply this patch which was made after the Mac font patch:
http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/3dabb2f78e73
Voila!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With