When creating a PDF using Apache FOP it is possible to embed a font with configuration file. The problem emerges when the app is a web application and it is necessary to embed a font that is inside WAR file (so treated as resource).
It is not acceptable to use particular container’s folder structure to determine where exactly the war is located (when in configuration xml file we set tag to ./
, it is set to the base folder of running container like C:Tomcatbin
).
So the question is: Do anyone know the way to embed a font programatically?
Advertisement
Answer
After going through lots of FOP java code I managed to get it to work.
Descriptive version
Main idea is to force FOP to use custom PDFRendererConfigurator
that will return desired font list when getCustomFontCollection()
is executed.
In order to do it we need to create custom PDFDocumentHandlerMaker
that will return custom PDFDocumentHandler
(form method makeIFDocumentHandler()
) which will in turn return our custom PDFRendererConfigurator
(from getConfigurator()
method) that, as above, will set out custom font list.
Then just add custom PDFDocumentHandlerMaker
to RendererFactory
and it will work.
FopFactory > RendererFactory > PDFDocumentHandlerMaker > PDFDocumentHandler > PDFRendererConfigurator
Full code
FopTest.java
public class FopTest { public static void main(String[] args) throws Exception { // the XSL FO file StreamSource xsltFile = new StreamSource( Thread.currentThread().getContextClassLoader().getResourceAsStream("template.xsl")); // the XML file which provides the input StreamSource xmlSource = new StreamSource( Thread.currentThread().getContextClassLoader().getResourceAsStream("employees.xml")); // create an instance of fop factory FopFactory fopFactory = new FopFactoryBuilder(new File(".").toURI()).build(); RendererFactory rendererFactory = fopFactory.getRendererFactory(); rendererFactory.addDocumentHandlerMaker(new CustomPDFDocumentHandlerMaker()); // a user agent is needed for transformation FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); // Setup output OutputStream out; out = new java.io.FileOutputStream("employee.pdf"); try { // Construct fop with desired output format Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); // Setup XSLT TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(xsltFile); // Resulting SAX events (the generated FO) must be piped through to // FOP Result res = new SAXResult(fop.getDefaultHandler()); // Start XSLT transformation and FOP processing // That's where the XML is first transformed to XSL-FO and then // PDF is created transformer.transform(xmlSource, res); } finally { out.close(); } } }
CustomPDFDocumentHandlerMaker.java
public class CustomPDFDocumentHandlerMaker extends PDFDocumentHandlerMaker { @Override public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { CustomPDFDocumentHandler handler = new CustomPDFDocumentHandler(ifContext); FOUserAgent ua = ifContext.getUserAgent(); if (ua.isAccessibilityEnabled()) { ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler()); } return handler; } }
CustomPDFDocumentHandler.java
public class CustomPDFDocumentHandler extends PDFDocumentHandler { public CustomPDFDocumentHandler(IFContext context) { super(context); } @Override public IFDocumentHandlerConfigurator getConfigurator() { return new CustomPDFRendererConfigurator(getUserAgent(), new PDFRendererConfigParser()); } }
CustomPDFRendererConfigurator.java
public class CustomPDFRendererConfigurator extends PDFRendererConfigurator { public CustomPDFRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { super(userAgent, rendererConfigParser); } @Override protected FontCollection getCustomFontCollection(InternalResourceResolver resolver, String mimeType) throws FOPException { List<EmbedFontInfo> fontList = new ArrayList<EmbedFontInfo>(); try { FontUris fontUris = new FontUris(Thread.currentThread().getContextClassLoader().getResource("UbuntuMono-Bold.ttf").toURI(), null); List<FontTriplet> triplets = new ArrayList<FontTriplet>(); triplets.add(new FontTriplet("UbuntuMono", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)); EmbedFontInfo fontInfo = new EmbedFontInfo(fontUris, false, false, triplets, null, EncodingMode.AUTO, EmbeddingMode.AUTO); fontList.add(fontInfo); } catch (Exception e) { e.printStackTrace(); } return createCollectionFromFontList(resolver, fontList); } }