我正在使用Flying Saucer将一些PDF文档从字符串渲染为XHTML。我的代码类似于:
iTextRenderer.setDocument(documentGenerator.generate(xhtmlDocumentAsString));
iTextRenderer.layout();
iTextRenderer.createPDF(outputStream);
我想要了解的是,在使用此方法时,XHTML中的相对路径从何处解决?例如,对于图像或样式表。我能够使用此方法成功生成基于文本的文档,但我需要了解如何引用我的图像和CSS。
答案 0 :(得分:18)
setDocument()方法有两个参数:document和url。 url参数指示用于添加到xhtml中出现的相对路径的基本URL,例如img标记。
假设你有:
<img src="images/img1.jpg">
现在假设文件夹“images”位于:
C:/physical/route/to/app/images/
您可以将setDocument()用作:
renderer.setDocument(xhtmlDoc, "file:///C:/physical/route/to/app/");
注意尾部斜杠,没有它就无法工作。
这是它对我有用的方式。我假设您可以使用其他类型的网址,例如“http:// ...”。
答案 1 :(得分:7)
这个星期我一直在研究这个问题,我告诉你什么对我有用。
在现实生活中,您的XHTML文档指向具有相对路径的多个资源(图像,css等)。 您还必须向Flying Saucer解释在哪里找到它们。它们可以位于类路径中,也可以位于文件系统中。 (如果他们在网络上,你可以设置基本网址,所以这没有帮助)
所以你必须像这样扩展ITextUserAgent:
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;
}
}
你这样使用它:
// 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();
干杯。
答案 2 :(得分:1)
AtilaUy的答案是飞碟中默认方式的正确答案。
更一般的答案是它询问UserAgentContext。在设置文档时,它将在UserAgentContext上调用setBaseURL()。然后,当它想要读取实际资源数据时,它将调用resolveURL()来解析相对URL并最终解析resolveAndOpenStream()。
嗯,这个答案对你来说可能为时已晚,但是当我出发时我需要这样的答案,设置自定义用户代理上下文是我最终使用的解决方案。
答案 3 :(得分:0)
您可以拥有文件路径,也可以是绝对路径,或http:// urls。相对路径可以工作,但不可移植,因为它取决于您从
运行程序的目录答案 4 :(得分:0)
我认为更简单的方法是:
DomNodeList<DomElement> images = result.getElementsByTagName("img");
for (DomElement e : images) {
e.setAttribute("src", result.getFullyQualifiedUrl(e.getAttribute("src")).toString());
}
答案 5 :(得分:0)
解决路径的另一种方法是覆盖UserAgentCallback#resolveURI
,它提供比固定URL更动态的行为(如AtilaUy的答案,在大多数情况下看起来非常有效)。
这就是我使用XHTMLPane
使用动态生成的样式表的方法:
public static UserAgentCallback interceptCssResourceLoading(
final UserAgentCallback defaultAgentCallback,
final Map< URI, CSSResource > cssResources
) {
return new UserAgentCallback() {
@Override
public CSSResource getCSSResource( final String uriAsString ) {
final URI uri = uriQuiet( uriAsString ) ; // Just rethrow unchecked exception.
final CSSResource cssResource = cssResources.get( uri ) ;
if( cssResource == null ) {
return defaultAgentCallback.getCSSResource( uriAsString ) ;
} else {
return cssResource ;
}
}
@Override
public String resolveURI( final String uriAsString ) {
final URI uri = uriQuiet( uriAsString ) ;
if( cssResources.containsKey( uri ) ) {
return uriAsString ;
} else {
return defaultAgentCallback.resolveURI( uriAsString ) ;
}
}
// Delegate all other methods to defaultUserAgentCallback.
} ;
}
然后我就这样使用它:
final UserAgentCallback defaultAgentCallback =
xhtmlPanel.getSharedContext().getUserAgentCallback() ;
xhtmlPanel.getSharedContext().setUserAgentCallback(
interceptCssResourceLoading( defaultAgentCallback, cssResources ) ) ;
xhtmlPanel.setDocumentFromString( xhtml, null, new XhtmlNamespaceHandler() ) ;
答案 6 :(得分:0)
对我来说最好的解决方案是:
'same'/'valid'
然后在html中提供所有提供的样式和图像(比如
renderer.setDocumentFromString(htmlContent, new ClassPathResource("/META-INF/pdfTemplates/").getURL().toExternalForm());
)按预期呈现。