Search code examples
pdfflying-saucer

Setting the URL resolver directory when using a generated XHTML document?


Here's my current workflow:

  1. Load POJOs from the database.
  2. Pass them into Velocity, rendering a HTML template in-memory.
  3. Then render the outputted HTML to a PDF using Flying Saucer and iText.

The problem occurs when I try to resolve relative URLs like images and the like. Since my document lives in memory, it doesn't know how to resolve images or stylesheets at all. How can I set the document for it to an in-memory String object while still passing it a directory to load resources from?

String velocityOutput = VelocityEngineUtils.mergeTemplateIntoString(...);

ByteArrayOutputStream output = new ByteArrayOutputStream(...);

ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(velocityOutput);
renderer.layout();
renderer.createPDF(output);

I need to do everything in-memory as I'm simply generating the report to be emailed to clients. How can I make an <img src="..."/> resolve a relative URL in my HTML template when generated to a PDF?


Solution

  • I ended up simply loading my document into a Java Document instance and then sending it to Flying Saucer with the resource directory in one call:

    Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
                    .parse(new ByteArrayInputStream(templateOutput.getBytes("UTF-8")));
    
    ITextRenderer renderer = new ITextRenderer();
    renderer.setDocument(document, templateResourceDirectory);
        renderer.layout();
    
    OutputStream result = new ByteArrayOutputStream();
    
    renderer.createPDF(result);
    

    One thing to be especially careful of is the fact that Flying Saucer needs file-based URIs to be prefixed with file://, and that it requires a slash at the end of the file path in order to work properly:

    /var/www/cache         # FAIL
    file:///var/www/cache  # ALSO FAIL
    file:///var/www/cache/ # WIN