9

我正在使用 Flying Saucer 将一些 PDF 文档从字符串呈现为 XHTML。我的代码是这样的:

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

我想了解的是,当使用这种方法时,XHTML 中的相对路径是从哪里解析的?例如,对于图像或样式表。我能够使用此方法成功生成基于文本的文档,但我需要了解如何引用我的图像和 CSS。

4

7 回答 7

20

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://...”。

于 2011-01-07T17:25:36.100 回答
8

本周我在这方面工作,我给你什么对我有用。

在现实生活中,您的 XHTML 文档指向具有相对路径的多个资源(图像、css 等)。您还必须向飞碟解释在哪里可以找到它们。它们可以在您的类路径中,也可以在您的文件系统中。(如果他们在网络上,你可以只设置基本 url,所以这无济于事)

所以你必须像这样扩展 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();

干杯。

于 2013-02-15T13:26:50.540 回答
2

对我来说最好的解决方案是:

renderer.setDocumentFromString(htmlContent,  new ClassPathResource("/META-INF/pdfTemplates/").getURL().toExternalForm());

然后是 html 中提供的所有样式和图像(比如

<img class="logo" src="images/logo.png" />
<link rel="stylesheet" type="text/css" media="all" href="css/style.css"></link>

) 按预期呈现。

于 2016-06-15T17:05:42.833 回答
1

AtilaUy 的回答是飞碟中默认的工作方式。

更一般的答案是它询问 UserAgentContext。当设置文档时,它将在 UserAgentContext 上调用 setBaseURL()。然后它会调用 resolveURL() 来解析相对 URL,并最终在要读取实际资源数据时调用 resolveAndOpenStream()。

好吧,无论如何,这个答案对于你来说可能已经太晚了,但是我在出发时需要这样的答案,而设置自定义用户代理上下文是我最终使用的解决方案。

于 2011-04-19T03:22:28.463 回答
0

您可以拥有文件路径(应该是绝对路径)或 http:// url。相对路径可以工作但不可移植,因为它取决于您从哪个目录运行程序

于 2011-03-16T15:27:41.077 回答
0

我认为更简单的方法是:

                DomNodeList<DomElement> images = result.getElementsByTagName("img");
                for (DomElement e : images) { 
                    e.setAttribute("src", result.getFullyQualifiedUrl(e.getAttribute("src")).toString());
                }
于 2014-07-30T14:42:03.490 回答
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() ) ;
于 2015-10-26T08:07:29.713 回答