If you’re using Apache FOP to create PDF/A you’re forced to embed all fonts (even the base 14 fonts). Generally there are two options how to embed the fonts:
- Let FOP auto-detect the fonts
- Create a font metrics file and tell FOP where to find it
Auto-detection is a pretty nice feature since FOP does the job to find and interpret the font. The major drawback of this solution is that FOP scans different places for fonts (the default font folders of the OS, every folder in “.” and it looks for special entries in MANIFEST.MF). This is done every time you create a new Fop instance. You can guess how that might effect an application if it’s creating lots of PDF files.
To improve the performance you can create font metrics files an tell FOP where to find them. Compared to auto-detection this is a cheap operation. But there’s also a drawback: URIs to the files have to absolute paths. Especially if you’re using different environments (Development, Testing, Pre-Production etc.) absolute paths are hard to find.
Wouldn’t it be nice if you can put your font files in a JAR and FOP just finds it? FOP can’t do it by default but you can teach FOP how to. First you have to implement an URIResolver:
import java.io.InputStream;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamSource;
public class ClasspathUriResolver implements URIResolver
{
public Source resolve(String href, String base) throws TransformerException
{
Source source = null;
InputStream inputStream = ClassLoader.getSystemResourceAsStream(href);
if (inputStream != null)
{
source = new StreamSource(inputStream);
}
return source;
}
}
The next step is to register this URIResolver as a custom URIResolver. You can access the default URIResolver via the FopFactory:
FopFactory fopFactory = FopFactory.newInstance(); FOURIResolver uriResolver = (FOURIResolver) fopFactory.getURIResolver(); uriResolver.setCustomURIResolver(new ClasspathUriResolver());
FOP now tries to find the font and metrics file with its built in feature and if no files are found the ClasspathUriResolver is called. If still no font can be found an PDFConformanceException is thrown.
The final step is to put your files somewhere in the classpath (best choice would be a JAR file). If you're putting them in a JAR file in the folder fonts the appropriate FOP config would look like:
<renderers>
<renderer mime="application/pdf">
<fonts>
<!-- Arial -->
<font
metrics-url="\fonts\arial.xml"
kerning="yes"
embed-url="\fonts\arial.ttf">
<font-triplet name="Arial" style="normal" weight="normal" />
<font-triplet name="ArialMT" style="normal" weight="normal" />
</font>
</fonts>
</renderer>
FOP now finds the font and can embed it. Since the file is loaded into the Classloader ever subsequent lookup is very fast. If you don't want to open an InputStream every time and you don't have many fonts you can cache the contents in a byte[] and put an ByteArrayInputStream in the StreamSource.
For comparison: When I use auto-detection creating a new Fop instance takes about 300 ms. Using predefined metrics files the instance is created < 20 ms.
Recent Comments