Java – Apache Batik 1.7 + Apache FOP 1.1 does not render fonts on Ubuntu

Apache Batik 1.7 + Apache FOP 1.1 does not render fonts on Ubuntu… here is a solution to the problem.

Apache Batik 1.7 + Apache FOP 1.1 does not render fonts on Ubuntu

I’m having trouble configuring fonts in apache batik + apache fop svg pdf transcoder.

The config file doesn’t seem to load correctly, but only on Ubuntu.
I’ve tried running the exact same code on MacOSX, it just
Very good….

Trying to load the same SVG on both systems produces different results.

The relevant part of Java is this:

try {
   DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
   Configuration effCfg = cfgBuilder.buildFromFile(new File(this.fontCfgFilePath));
   if (effCfg != null) {
        PDFDocumentGraphics2DConfigurator configurator = new PDFDocumentGraphics2DConfigurator();
        configurator.configure(graphics, effCfg, false);
   } else {
        graphics.setupDefaultFontInfo();
   }
} catch (Exception e) {
   throw new TranscoderException("Error while setting up PDFDocumentGraphics2D", e);
}

But the full version is only a slightly modified version

https://github.com/naofum/thinreports-java/blob/master/src/com/github/naofum/thinreports/MultiPagePDFTranscoder.java

The only difference is how the configuration file is delivered. In the original version, the config file was hard-coded, and in my version, the config file was passed in through the constructor.

this.fontCfgFilePath is set to “resources/fonts.cfg.xml” in the constructor

The folder structure is

project/
   resources/
      font.cfg.xml
      fonts/
         0b0b385a-f6e8-4a33-887f-2f178a576139.ttf
         ... a bunch of other fonts ....
   pdf-generator.jar
   ... other files that are not relevant to the problem...

font.cfg.xml is set up like this

<configuration>
  <fonts>
    ... other fonts ....
    <font kerning="no" embed-url="file:resources/fonts/0b0b385a-f6e8-4a33-887f-2f178a576139.ttf">
        <font-triplet name="Papyrus" style="normal" weight="normal"></font-triplet>
    </font>
    <font kerning="no" embed-url="file:resources/fonts/0b0b385a-f6e8-4a33-887f-2f178a576139.ttf">
        <font-triplet name="Papyrus" style="normal" weight="bold"></font-triplet>
    </font>
    <font kerning="no" embed-url="file:resources/fonts/0b0b385a-f6e8-4a33-887f-2f178a576139.ttf">
        <font-triplet name="Papyrus" style="italic" weight="normal"></font-triplet>
    </font>
    <font kerning="no" embed-url="file:resources/fonts/0b0b385a-f6e8-4a33-887f-2f178a576139.ttf">
        <font-triplet name="Papyrus" style="italic" weight="bold"></font-triplet>
    </font>
    ... other fonts
  </fonts>
</configuration>

If running on both Ubuntu and MacOSX, the exact same project with exactly the same configuration.

MacOSX produces the right PDF with the right font

Ubuntu does not…

Interestingly, Ubuntu doesn’t even try to use fonts….

If I remove a font from my profile on my mac, it won’t render it as expected

If I change the font file to something invalid, again on the Mac, it throws FileNotFoundException.

But on Ubuntu none of that matters… Basically, it looks like the font file has never been read.

I’ve tried adding fonts directly to the system (in /usr/share/fonts) and forcing an update of the font cache on ubuntu using “fc-cache -fv”, but that didn’t help.

I also tried various embedded url links (in config) but nothing worked (i.e. embed-url=”file://resources…” to embed-url=”file:///resources…” and other variants).

Both systems run Java 1.8 (ubuntu on Oracle JDK 1.8.151

, Mac on Oracle JDK 1.8.131).

Solution

After searching extensively on the web and reading the source code of batik/fop and java itself, I found that Batik and FOP needed to display fonts in java.awt.GraphicsEnvironment

java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment() 

You get an instance of GraphicsEnvironment on which you can call

ge.getAvailableFontFamilyNames()

Gets an array of currently loaded font families.

Note that .ttf fonts load correctly without defining a font family.

But Batik and FOP DO need to specify the correct font family….

It happens that MacOSX knows (when installing system-level fonts) to set the correct font family. But GNU/Linux doesn’t seem to do the same thing.

If the font is not available system-wide (which is my case on Linux), you must register it in Java.

This can be done like this using GraphicsEnvironment:

boolean loaded = ge.registerFont(java.awt.Font.createFont(java.awt.Font/TRUETYPE_FONT, new File("<path to font>"));

If loaded is

true, the font is loaded correctly and it will be registered in batik/fop and rendered correctly.
Note that the font .cfg.xml (a problem with self) still needs to exist and the font path needs to match the registered font.

If loaded is

false, the font is not loaded.

The main reason seems to be that fonts with the same font family or the same font name are already registered. (See here .) http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/font/FontManager.java#2921)

It’s also important to register fonts before any rendering happens because batik/fop caches fonts somewhere and doesn’t flush them.

My solution was to remove the system fonts and keep the local fonts.

So my question is

  1. None of my .ttf fonts have the appropriate font family defined

  2. The font is not properly registered in Java.

My solution is

  1. For 1. Use fontforge to add the correct font family for all my fonts.
  2. For 2. Register all my fonts in GraphicsEnvironment as mentioned above.
  3. Extra steps. Remove all old fonts (those that don’t have the correct font family) from my ubuntu system as I added them to see if it fixes anything.

Related Problems and Solutions