2015-12-22 4 views
1

Je crée des documents PDF avec iTextSharp (5.5.7.0) à partir de HTML dans l'application ASP.NET MVC5, mais je ne parviens pas à changer la police. J'ai essayé presque tout ce que j'ai pu trouver sur SO ou à partir d'autres ressources.Conversion HTML vers PDF iTextSharp - impossible de changer de police

code pour la génération PDF est la suivante:

public Byte[] GetRecordsPdf(RecordsViewModel model) 
    { 
     var viewPath = "~/Template/RecordTemplate.cshtml"; 
     var renderedReport = RenderViewToString(viewPath, model); 

     FontFactory.RegisterDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Fonts)); 

     using (var ms = new MemoryStream()) 
     { 
      using (var doc = new Document()) 
      { 
       doc.SetPageSize(PageSize.A4.Rotate()); 

       using (var writer = PdfWriter.GetInstance(doc, ms)) 
       { 
        doc.Open(); 

        using (var html = new MemoryStream(Encoding.Default.GetBytes(renderedReport))) 
        { 
         XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, html, Encoding.Default); 
        } 

        doc.Close(); 
       } 
      } 

      var bytes = ms.ToArray(); 
      return bytes; 
     } 
    } 

HTML réel est contenu dans la variable de chaîne renderedReport (je fortement fichier .cshtml typé que je rends en utilisant le moteur MVC Razor puis revenir HTML dans la chaîne).

J'ai essayé d'enregistrer certaines polices spécifiques, mais cela n'a pas aidé. J'ai également essayé d'enregistrer toutes les polices sur ma machine (comme montré dans l'exemple ci-dessus), mais cela n'a pas aidé non plus. Les polices ont été chargées J'ai vérifié cela en mode debug.

CSS est intégré dans le fichier HTML (en-tête, balise de style) comme ceci:

body { 
     font-size: 7px; 
     font-family: Comic Sans MS; 
    } 

(pour le test, je l'ai décidé d'utiliser Comic Sans, parce que je peux le reconnaître avec facilité, je m plus intéressé par Arial Unicode MS en fait).

Et je suis réellement en mesure de changer la police avec cet attribut font-family de CSS, mais seulement à partir de polices qui sont préchargées par iTextSharp par défaut - Times New Roman, Arial, Courier, et d'autres (Helvetica i pense). Lorsque je le change en - Comic Sans, ou un autre qui n'est pas préchargé iTextSharp rend avec la police par défaut (Arial je dirais).

La raison pour laquelle j'ai besoin de changer la police est parce que j'ai quelques caractères croates dans mon HTML rendu (ČÃŠĐŽčćšđž) qui manquent du pdf, et actuellement je pense que la raison principale est - police.

Qu'est-ce qui me manque?

Répondre

5

Un couple de choses pour que cela fonctionne.

D'abord, XMLWorkerHelper n'utilise pas FontFactory par défaut, vous devez utiliser l'une des surcharges pour ParseXHtml() qui prend un IFontProvider. Ces deux surcharges nécessitent que vous spécifiez un Stream pour un fichier CSS, mais vous pouvez simplement passer null si votre CSS vit dans votre fichier HTML. Heureusement FontFactory a une propriété statique qui implémente ce que vous pouvez utiliser appelé FontFactory.FontImp

//                     **This guy** 
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, null, Encoding.UTF8, FontFactory.FontImp); 

Deuxièmement, je sais que vous avez dit que vous avez essayé l'enregistrement de votre répertoire complet de la police en désespoir de cause, mais qui peut être un appel assez cher. Si vous le pouvez, essayez toujours de simplement enregistrer les polices dont vous avez besoin. Bien que facultatif, je vous recommande fortement de définir explicitement l'alias de la police car les polices peuvent avoir plusieurs noms et ne sont pas toujours ce que nous pensons.

FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS"); 

En troisième lieu, et cela pourrait ne pas vous affecter, mais aucune balise ne figure pas dans le code HTML, même si elles sont logiquement implicite, ne sera pas un style qui leur est appliqué à partir de CSS. Cela semble bizarre, pour le dire autrement, si votre HTML est juste <p>Hello</p> et que votre CSS est body{font-size: 7px;}, la taille de la police ne sera pas appliquée car votre code HTML manque de la balise <body>.Quatrième, et ceci est facultatif, mais il est généralement plus facile de spécifier votre HTML et CSS séparément les uns des autres, ce que je ferai dans l'exemple ci-dessous.

Votre code était 95% là-bas, donc avec quelques ajustements, cela devrait fonctionner. Au lieu d'une vue, je suis juste en train d'analyser le HTML et le CSS bruts mais vous pouvez les modifier au besoin. S'il vous plaît rappelez-vous (et je pense que vous le savez) que iTextSharp ne peut pas traiter ASP.Net, seulement HTML, donc vous devez vous assurer que votre processus de conversion ASP.Net vers HTML est sain.

//Sample HTML and CSS 
var html = @"<body><p>Sva ljudska bića rađaju se slobodna i jednaka u dostojanstvu i pravima. Ona su obdarena razumom i sviješću i trebaju jedna prema drugima postupati u duhu bratstva.</p></body>"; 
var css = "body{font-size: 7px; font-family: Comic Sans MS;}"; 

//Register a single font 
FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS"); 

//Placeholder variable for later 
Byte[] bytes; 

using (var ms = new MemoryStream()) { 
    using (var doc = new Document()) { 
     doc.SetPageSize(PageSize.A4.Rotate()); 

     using (var writer = PdfWriter.GetInstance(doc, ms)) { 
      doc.Open(); 

      //Get a stream of our HTML 
      using (var msHTML = new MemoryStream(Encoding.UTF8.GetBytes(html))) { 

       //Get a stream of our CSS 
       using (var msCSS = new MemoryStream(Encoding.UTF8.GetBytes(css))) { 

        XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, msCSS, Encoding.UTF8, FontFactory.FontImp); 
       } 
      } 

      doc.Close(); 
     } 
    } 

    bytes = ms.ToArray(); 
} 
+1

Thx en réponse. Puisque cela change vraiment ma police en pdf c'est une réponse acceptée. Je n'étais pas du tout conscient que XmlWorker n'utilisait pas FontFactory par défaut. Mais il semble que j'étais sur la mauvaise piste en ce qui concerne les caractères croates - il ne s'agit pas de police. Actuellement, il semble que FontFactory par défaut charge toutes les polices avec un encodage CP1252 (si ce n'est pas le cas), et je devrais utiliser Identity_H. Des idées comment faire cela? – Franko

+1

En guise de remarque, je proposerais de ne pas mettre le 'PdfWriter' dans une directive' using'. Si aucune erreur ne se produit, le writer est implicitement fermé par le 'doc.Close', et si quelque erreur se produit, le' PdfWriter' est éliminé * avant le * Document' qui causera probablement des erreurs supplémentaires quand ce dernier est éliminé, et ces erreurs supplémentaires masquent les erreurs d'origine. – mkl

+0

@Franko Vous l'avez probablement déjà compris, mais vous pouvez changer l'encodage en Identity_H si vous créez un nouveau XMLWorkerFontProvider, c'est-à-dire 'var fontImp = new iTextSharp.tool.xml.XMLWorkerFontProvider (" votre_font_directory "); fontImp.DefaultEncoding = "Identity-H"; 'et ensuite utiliser' fontImp' au lieu de 'FontFactory.FontImp'. – jahu