I'm using flyingsaucer to render an xhtml document to pdf through a servlet which returns the generated pdf document. The xhtml document features an image which is requested from another servlet. The image servlet checks who is logged in before returning the appropriate image. The code below shows how the image is requested:
<img height="140" width="140" src="http://localhost:8080/myapp/servlet/DisplayPic" />
My problem is that the http request for the image is from the pdf renderer and not the logged in user so the image servlet doesn't know who's logged in and therefore the desired image is not returned.
I'm currently using the code below to render the xhtml document:
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(xhtmlDocumentAsString);
renderer.layout();
os = response.getOutputStream();
renderer.createPDF(os);
I need to either maintain the user's session when the image servlet is requested or provide the renderer with the image to use for that specific xhtml element. I think the latter can be done using a ReplacedElementFactory
but I haven't been able to dig out any example code that can help me.
I've got this working very nicely now. Here's the code.
In my xhtml document i have:
<div class="profile_picture" style="display:block;width:140px;height:140px;" />
(I'm using a div
element instead of img
as the factory is only used for block level elements)
I render my document using:
ITextRenderer renderer = new ITextRenderer();
renderer.getSharedContext().setReplacedElementFactory(new ProfileImageReplacedElementFactory(renderer.getSharedContext().getReplacedElementFactory()));
renderer.setDocumentFromString(xhtmlDocumentAsString);
renderer.layout();
os = response.getOutputStream();
renderer.createPDF(os);
And i have my own ReplacedElementFactory
as below:
public class ProfileImageReplacedElementFactory implements ReplacedElementFactory {
private final ReplacedElementFactory superFactory;
public ProfileImageReplacedElementFactory(ReplacedElementFactory superFactory) {
this.superFactory = superFactory;
}
@Override
public ReplacedElement createReplacedElement(LayoutContext layoutContext, BlockBox blockBox,
UserAgentCallback userAgentCallback, int cssWidth, int cssHeight) {
Element element = blockBox.getElement();
if (element == null) {
return null;
}
String nodeName = element.getNodeName();
String className = element.getAttribute("class");
if ("div".equals(nodeName) && className.contains("profile_picture")) {
InputStream input = null;
try {
input = ...;
byte[] bytes = IOUtils.toByteArray(input);
Image image = Image.getInstance(bytes);
FSImage fsImage = new ITextFSImage(image);
if (fsImage != null) {
if ((cssWidth != -1) || (cssHeight != -1)) {
fsImage.scale(cssWidth, cssHeight);
}
return new ITextImageElement(fsImage);
}
} catch (IOException e) {
getLogger().error(ExceptionUtils.getStackTrace(e));
} catch (BadElementException e) {
getLogger().error(ExceptionUtils.getStackTrace(e));
} finally {
IOUtils.closeQuietly(input);
}
}
return superFactory.createReplacedElement(layoutContext, blockBox, userAgentCallback, cssWidth, cssHeight);
}
@Override
public void reset() {
superFactory.reset();
}
@Override
public void remove(Element e) {
superFactory.remove(e);
}
@Override
public void setFormSubmissionListener(FormSubmissionListener listener) {
superFactory.setFormSubmissionListener(listener);
}
}