2010-03-04 13 views
5

J'utilise Flying Saucer pour rendre certains documents PDF de chaînes en XHTML. Mon code est quelque chose comme:Chemins relatifs dans la soucoupe volante XHTML?

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

Ce que je suis en train de comprendre est, lors de l'utilisation de cette méthode, où sont les chemins relatifs dans le XHTML résolus à partir? Par exemple, pour les images ou les feuilles de style. Je suis capable d'utiliser cette méthode pour générer avec succès un document textuel, mais j'ai besoin de comprendre comment référencer mes images et CSS.

Répondre

14

La méthode setDocument() prend deux paramètres: document et url. Le paramètre url indique l'URL de base utilisée pour préfixer les chemins relatifs qui apparaissent dans le xhtml, comme dans les balises img.

Supposons que vous avez:

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

Supposons maintenant le dossier "images" est situé à:

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

Vous pouvez utiliser setDocument() comme:

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

Notez que le barre oblique, ça ne marchera pas sans ça.

Voici comment cela a fonctionné pour moi. Je suppose que vous pourriez utiliser d'autres types d'URL tels que "http: // ...".

0

Vous pouvez avoir des chemins de fichiers, qui doivent être absolus, ou http: // urls. Les chemins relatifs peuvent fonctionner mais ne sont pas portables, car cela dépend du répertoire dans lequel vous avez exécuté votre programme.

1

La réponse d'AtilaUy est juste pour les choses par défaut dans Flying Saucer.

La réponse plus générale est qu'elle demande le UserAgentContext. Il appellera setBaseURL() sur le UserAgentContext lorsque le document est défini. Ensuite, il appellera resolveURL() pour résoudre les URL relatives et finalement resolveAndOpenStream() lorsqu'il veut lire les données de ressources réelles. Eh bien, cette réponse est probablement trop tardive pour que vous puissiez l'utiliser de toute façon, mais j'avais besoin d'une réponse comme celle-ci quand je suis parti, et la définition d'un contexte d'agent utilisateur personnalisé est la solution que j'ai utilisée.

5

Cette semaine, j'ai travaillé sur ce sujet, et je vous donne ce qui a bien fonctionné pour moi.

Dans la réalité, votre document XHTML pointe vers plusieurs ressources (images, css, etc.) avec des chemins relatifs. Vous devez également expliquer à la soucoupe volante où les trouver. Ils peuvent être dans votre classpath, ou dans votre système de fichiers. (S'ils sont sur le réseau, vous pouvez simplement définir l'URL de base, donc ce ne sera pas aider)

Vous devez étendre le ITextUserAgent comme ceci:

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; 
    } 
} 

Et vous l'utiliser comme ceci :

// 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(); 

Cheers.

0

Je pense qu'une approche plus facile serait:

   DomNodeList<DomElement> images = result.getElementsByTagName("img"); 
       for (DomElement e : images) { 
        e.setAttribute("src", result.getFullyQualifiedUrl(e.getAttribute("src")).toString()); 
       } 
0

Une autre façon de résoudre les chemins est de passer outre UserAgentCallback#resolveURI, qui offre un comportement plus dynamique qu'une URL fixe (comme dans la réponse de AtilaUy, qui semble tout à fait valable pour la plupart des cas).

Voilà comment je fais un XHTMLPane utiliser des feuilles de style générées dynamiquement

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. 

    } ; 
} 

Puis-je utiliser comme ça:

final UserAgentCallback defaultAgentCallback = 
     xhtmlPanel.getSharedContext().getUserAgentCallback() ; 
    xhtmlPanel.getSharedContext().setUserAgentCallback(
     interceptCssResourceLoading(defaultAgentCallback, cssResources)) ; 
    xhtmlPanel.setDocumentFromString(xhtml, null, new XhtmlNamespaceHandler()) ; 
0

La meilleure solution pour moi était:

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

Alors tous les styles et les images fournies en html (comme

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

) ont été rendus comme prévu.

+0

Cette solution doit être basée sur le ressort. –