Относительные пути в Летающей тарелке XHTML? - PullRequest
7 голосов
/ 04 марта 2010

Я использую Flying Saucer для рендеринга некоторых документов PDF из строк в XHTML. Мой код что-то вроде:

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

Что я пытаюсь понять, при использовании этого метода, откуда разрешаются относительные пути в XHTML? Например, для изображений или таблиц стилей. Я могу использовать этот метод для успешного создания текстового документа, но мне нужно понять, как ссылаться на мои изображения и CSS.

Ответы [ 7 ]

18 голосов
/ 07 января 2011

Метод setDocument () принимает два параметра: document и url. Параметр url указывает базовый URL, используемый для добавления к относительным путям, которые появляются в xhtml, например в тегах img.

Предположим, у вас есть:

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

Теперь предположим, что папка "images" находится по адресу:

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

Вы можете использовать setDocument () как:

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

Обратите внимание на косую черту, без нее не получится.

Вот так у меня и получилось. Я предполагаю, что вы могли бы использовать другие типы URL, такие как "http: // ...".

7 голосов
/ 15 февраля 2013

На этой неделе я работал над этим, и я даю вам то, что хорошо работало для меня.

В реальной жизни ваш документ XHTML указывает на несколько ресурсов (изображения, CSS и т. Д.) С относительными путями. Вы также должны объяснить Летающей тарелке, где их найти. Они могут быть в вашем classpath или в вашей файловой системе. (Если они находятся в сети, вы можете просто установить базовый 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();

Приветствие.

1 голос
/ 19 апреля 2011

Ответ AtilaUy точен для стандартного способа, которым все работает в Летающей тарелке.

Более общий ответ заключается в том, что он запрашивает UserAgentContext. Он будет вызывать setBaseURL () для UserAgentContext, когда документ задан. Затем он будет вызывать resolURL () для разрешения относительных URL-адресов и, в конечном счете, resolAndOpenStream (), когда захочет прочитать фактические данные ресурса.

Что ж, этот ответ, вероятно, слишком поздно для вас, чтобы использовать его в любом случае, но мне нужно было получить ответ, подобный этому, когда я начал, и настройка пользовательского контекста агента пользователя - это решение, которое я в конечном итоге использовал.

0 голосов
/ 15 июня 2016

Лучшее решение для меня было:

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>

) были обработаны, как и ожидалось.

0 голосов
/ 26 октября 2015

Другим способом разрешения путей является переопределение 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() ) ;
0 голосов
/ 30 июля 2014

Я думаю, что более простой подход будет:

                DomNodeList<DomElement> images = result.getElementsByTagName("img");
                for (DomElement e : images) { 
                    e.setAttribute("src", result.getFullyQualifiedUrl(e.getAttribute("src")).toString());
                }
0 голосов
/ 16 марта 2011

У вас могут быть пути к файлам, которые должны быть абсолютными, или http: // urls. Относительные пути могут работать, но не переносимы, потому что это зависит от того, из какого каталога вы запустили программу из

...