Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading some TrueType Font from TTF file in Java causes FontFormatException: Font name not found

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.

like image 753
Nathan Smith Avatar asked Mar 21 '23 21:03

Nathan Smith


2 Answers

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!

like image 80
Nathan Smith Avatar answered Apr 25 '23 08:04

Nathan Smith


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!

like image 29
Roland Quast Avatar answered Apr 25 '23 10:04

Roland Quast