Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Relative paths in Flying Saucer XHTML?

I am using Flying Saucer to render some PDF documents from strings to XHTML. My code is something like:

iTextRenderer.setDocument(documentGenerator.generate(xhtmlDocumentAsString));
iTextRenderer.layout();
iTextRenderer.createPDF(outputStream);

What I'm trying to understand is, when using this method, where are relative paths in the XHTML resolved from? For example, for images or stylesheets. I am able to use this method to successfully generate a text-based document, but I need to understand how to reference my images and CSS.

like image 844
Adam Burley Avatar asked Mar 04 '10 10:03

Adam Burley


2 Answers

The setDocument() method takes two parameters: document and url. The url parameter indicates the base url used to prepend to relative paths that appear in the xhtml, such as in img tags.

Suppose you have:

<img src="images/img1.jpg">

Now suppose the folder "images" is located at:

C:/physical/route/to/app/images/

You may use setDocument() as:

renderer.setDocument(xhtmlDoc, "file:///C:/physical/route/to/app/");

Notice the trailing slash, it won't work without it.

This is the way it worked for me. I assume you could use other types of urls such as "http://...".

like image 82
AtilaUy Avatar answered Oct 02 '22 13:10

AtilaUy


This week I worked on this, and I give you what worked fine for me.

In real life, your XHTML document points to multiple resources (images, css, etc.) with relative paths. You also have to explain to Flying Saucer where to find them. They can be in your classpath, or in your file system. (If they are on the network, you can just set the base url, so this won't help)

So you have to extend the ITextUserAgent like this:

private static class ResourceLoaderUserAgent extends ITextUserAgent {

    public ResourceLoaderUserAgent(ITextOutputDevice outputDevice) {
        super(outputDevice);
    }

    protected InputStream resolveAndOpenStream(String uri) {

        InputStream is = super.resolveAndOpenStream(uri);
        String fileName = "";
        try {
            String[] split = uri.split("/");
            fileName = split[split.length - 1];
        } catch (Exception e) {
            return null;
        }

        if (is == null) {
            // Resource is on the classpath
            try{
                is = ResourceLoaderUserAgent.class.getResourceAsStream("/etc/images/" + fileName);
            } catch (Exception e) {
        }

        if (is == null) {
            // Resource is in the file system
            try {
                is = new FileInputStream(new File("C:\\images\\" + fileName));
            } catch (Exception e) {
            }
        }

        return is;
    }
}

And you use it like this:

// Output stream containing the result
ByteArrayOutputStream baos = new ByteArrayOutputStream();

ITextRenderer renderer = new ITextRenderer();
ResourceLoaderUserAgent callback = new ResourceLoaderUserAgent(renderer.getOutputDevice());
callback.setSharedContext(renderer.getSharedContext());
renderer.getSharedContext().setUserAgentCallback(callback);

renderer.setDocumentFromString(htmlSourceAsString);

renderer.layout();
renderer.createPDF(baos);
renderer.finishPDF();

Cheers.

like image 39
Remy Avatar answered Oct 02 '22 14:10

Remy