Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set base url in Flying-Saucer, while rendering HTML to PDF?

I am trying to render a HTML page to PDF using Flying-Saucer. The HTML is created in memory and passed to the renderer as

renderer.setDocumentFromString(new String(htmlByteArray));

The issue is that I have <img src="images.jpg"/> in the HTML and it is not getting rendered in the final HTML. The image is located in the resources folder in the package.

I tried setting the base url with the following, but with no success:

ITextRenderer renderer = new ITextRenderer();
renderer.getSharedContext().setBaseURL("com/org/tools/designer/resources/");
System.out.println(renderer.getSharedContext().getBaseURL());
renderer.setDocumentFromString(new String(htmlByteArray));
renderer.layout();
renderer.createPDF(os);
like image 908
raghurok Avatar asked Dec 06 '11 14:12

raghurok


1 Answers

Theres a really cool interface in FS called UserAgentCallback that allows you to get all your own resources. For other people looking at this you can set your url accordingly:

renderer.getSharedContext().getUserAgentCallback().setBaseURL("url_to_resources");

However you have a special case here, you have resources embedded inside your jar file that need a special way to be accessed. You can implement your own UserAgentCallback Heres a little one I wrote up for you. (I did not test this so you may have to debug it a bit).

This code bit extends the ITextUserAgent that way you only have to overwrite the getBinaryResource method and leave the rest up to the library. If this isnt working out you can look into implementing a full on UserAgentCallback.

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.xhtmlrenderer.pdf.ITextOutputDevice;
import org.xhtmlrenderer.pdf.ITextUserAgent;

public class PackageUserAgentCallback extends ITextUserAgent {
    private Class resourceClass;

    public PackageUserAgentCallback(ITextOutputDevice outputDevice, Class resourceClass) {
        super(outputDevice);
        this.resourceClass = resourceClass;
    }

    @Override
    public byte[] getBinaryResource(String uri) {
        try {
            InputStream in = resourceClass.getResourceAsStream(uri);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int numRead;
            byte [] buffer = new byte[256];
            while((numRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, numRead);
            }
            return out.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}

Then you can set this to your UserAgentCallback, this would direct all resource requests through your PackageUserAgentCallback

ITextRenderer renderer = new ITextRenderer();
renderer.getSharedContext().setUserAgentCallback(
        new PackageUserAgentCallback(renderer.getOutputDevice(), Resources.class));
System.out.println(renderer.getSharedContext().getBaseURL());
renderer.setDocumentFromString(new String(htmlByteArray));

renderer.layout();
renderer.createPDF(os);
like image 156
ug_ Avatar answered Oct 14 '22 08:10

ug_