web-dev-qa-db-fra.com

Utiliser itextsharp xmlworker pour convertir du HTML en PDF et écrire du texte verticalement

Est-il possible d’obtenir l’écriture de la direction du texte de bas en haut dans xmlworker? Je voudrais l'utiliser dans la table. Mon code est 

     <table border=1>
     <tr>
     <td style="padding-right:18px">
          <p style="writing-mode:sideways-lr;text-align:center">First</p</td>
     <td style="padding-right:18px">
          <p style="writing-mode:sideways-lr;text-align:center">Second</p></td></tr>
     <tr><td><p style="text-align:center">1</p>  </td>
         <td><p style="text-align:center">2</p></td> 
     </tr>
        </table>

Mais cela ne fonctionne pas après la conversion de HTML en PDF. Les textes FIRST et SECOND ne sont pas orientés de bas en haut.

9
Daniel

C'était un problème assez intéressant, donc +1 à la question. 

La première étape consistait à rechercher si iTextSharp XML Worker prenait en charge la balise HTMLtd. Les mappages peuvent être trouvés dans le source dans iTextSharp.tool.xml.html.Tags . Là, vous trouvez que td est associé à iTextSharp.tool.xml.html.table.TableData , ce qui facilite un peu la tâche de mise en œuvre d’un processeur de balises personnalisé. C'est à dire. tout ce que nous devons faire hérite de la classe et substitue End():

public class TableDataProcessor : TableData
{
    /*
     * a **very** simple implementation of the CSS writing-mode property:
     * https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode
     */
    bool HasWritingMode(IDictionary<string, string> attributeMap)
    {
        bool hasStyle = attributeMap.ContainsKey("style");
        return hasStyle
                && attributeMap["style"].Split(new char[] { ';' })
                .Where(x => x.StartsWith("writing-mode:"))
                .Count() > 0
            ? true : false;
    }

    public override IList<IElement> End(
        IWorkerContext ctx,
        Tag tag,
        IList<IElement> currentContent)
    {
        var cells = base.End(ctx, tag, currentContent);
        var attributeMap = tag.Attributes;
        if (HasWritingMode(attributeMap))
        {
            var pdfPCell = (PdfPCell) cells[0];
            // **always** 'sideways-lr'
            pdfPCell.Rotation = 90;
        }
        return cells;
    }
}

Comme indiqué dans les commentaires en ligne, il s'agit d'une très implémentation pour vos besoins spécifiques. Vous devez ajouter une logique supplémentaire pour prendre en charge toute autre valeur de la propriété write-modeCSS , et inclure tous les contrôles de cohérence.

METTRE À JOUR

D'après le commentaire laissé par @Daniel , il n'est pas clair d'ajouter CSS personnalisé lors de la conversion de HTML en PDF. D'abord le code HTML mis à jour:

string XHTML = @"
<h1>Table with Vertical Text</h1>
<table><tr>
<td style='writing-mode:sideways-lr;text-align:center;width:40px;'>First</td>
<td style='writing-mode:sideways-lr;text-align:center;width:40px;'>Second</td></tr>
<tr><td style='text-align:center'>1</td>
<td style='text-align:center'>2</td></tr></table>

<h1>Table <u>without</u> Vertical Text</h1>
<table width='50%'>
<tr><td class='light-yellow'>0</td></tr>
<tr><td>1</td></tr>
<tr><td class='light-yellow'>2</td></tr>
<tr><td>3</td></tr>
</table>";

Ensuite, un petit extrait de CSS personnalisé:

string CSS = @"
    body {font-size: 12px;}
    table {border-collapse:collapse; margin:8px;}
    .light-yellow {background-color:#ffff99;}
    td {border:1px solid #ccc;padding:4px;}
";

La partie légèrement difficile est la configuration supplémentaire - vous ne pouvez pas utiliser la simple XMLWorkerHelper.GetInstance().ParseXHtml() prête à l'emploi, couramment vue ici chez SO. Voici une méthode d'assistance simple qui devrait vous aider à démarrer:

public void ConvertHtmlToPdf(string xHtml, string css)
{
    using (var stream = new FileStream(OUTPUT_FILE, FileMode.Create))
    {
        using (var document = new Document())
        {
            var writer = PdfWriter.GetInstance(document, stream);
            document.Open();

            // instantiate custom tag processor and add to `HtmlPipelineContext`.
            var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
            tagProcessorFactory.AddProcessor(
                new TableDataProcessor(), 
                new string[] { HTML.Tag.TD }
            );
            var htmlPipelineContext = new HtmlPipelineContext(null);
            htmlPipelineContext.SetTagFactory(tagProcessorFactory);

            var pdfWriterPipeline = new PdfWriterPipeline(document, writer);
            var htmlPipeline = new HtmlPipeline(htmlPipelineContext, pdfWriterPipeline);

            // get an ICssResolver and add the custom CSS
            var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(true);
            cssResolver.AddCss(css, "utf-8", true);
            var cssResolverPipeline = new CssResolverPipeline(
                cssResolver, htmlPipeline
            );

            var worker = new XMLWorker(cssResolverPipeline, true);
            var parser = new XMLParser(worker);
            using (var stringReader = new StringReader(xHtml))
            {
                parser.Parse(stringReader);
            }
        }
    }
}

Au lieu de reprendre l'explication de l'exemple de code ci-dessus, consultez la documentation (documentation retirée d'iText, liée à Wayback Machine) pour avoir une meilleure idée de la raison pour laquelle vous devez configurer l'analyseur de cette façon.

Notez aussi:

  1. XML Worker ne supporte pas toutes les propriétés CSS2/CSS3, de sorte que vous pouvez devez expérimenter avec ce qui fonctionne ou ne fonctionne pas en ce qui concerne la proximité avec laquelle vous souhaitez que le PDF ait l'air au code HTML affiché dans le navigateur.
  2. L'extrait HTML a supprimé la balise p, car le style peut être appliqué directement à la balise td.
  3. La propriété inline width. Si omis, les colonnes auront des largeurs variables qui correspondent si le texte a été rendu horizontalement.

Testé avec les versions de iTextSharp et XML Worker 5.5.9 Voici le résultat de updated:

 enter image description here

8
kuujinbo

comment rendre les tags d'image à l'intérieur de la table en pdf selon leur emplacement dans la table? - @kuujinbo

<table cellpadding="30" class="table table-striped" id="StudentInfoListTable">
                        <tr>
                            <td><img src="@Model.img" alt="" height="200" width="200" /></td>
                            <td class="middle"></td>
                            <td>LICENSE ID - @Html.DisplayFor(m => m.LicenseID)</td>
                        </tr>
                        <tr>
                            <td>NAME: </td>
                            <td class="middle"></td>
                            <td>@Html.DisplayFor(m => m.Name)</td>
                        </tr>
                        <tr>
                            <td>@Html.DisplayFor(m => m.Relo) </td>
                            <td class="middle"></td>
                            <td>@Html.DisplayFor(m => m.careOf)</td>
                        </tr>
                        <tr>
                            <td>GENDER: </td>
                            <td class="middle"></td>
                            <td>@Html.DisplayFor(m => m.gender)</td>
                        </tr>
                        <tr>
                            <td>BLOOD GROUP: </td>
                            <td class="middle"></td>
                            <td>@Html.DisplayFor(m => m.blood)</td>
                        </tr>
                        <tr>
                            <td>DATE OF BIRTH: </td>
                            <td class="middle"></td>
                            <td>@Html.DisplayFor(m => m.date)</td>
                        </tr>
                        <tr>
                            <td>CONTACT NO: </td>
                            <td class="middle"></td>
                            <td>@Html.DisplayFor(m => m.Mobile)</td>
                        </tr>
                        <tr>
                            <td>ADDRESS: </td>
                            <td class="middle"></td>
                            <td>@Html.DisplayFor(m => m.Address)</td>
                        </tr>
                        <tr>
                            <td>Signature </td>
                            <td class="middle"></td>
                            <td><img src="@Model.sign" alt="" style="background-color:white;"/></td>
                        </tr>
                    </table>
0
Siddarth Dutta
public void addHtmlToPdf(Document document, PdfWriter writer, String html) {
    PdfPTable table = new PdfPTable(1);
    PdfPCell cell = new PdfPCell();
    ElementList list = XMLWorkerHelper.ParseToElementList(html, null);
    foreach(IElement element in list) {
        cell.AddElement(element);
    }
    table.AddCell(cell);
    document.Add(table);
}

Alternative avec utf8:

public void addHtmlToPdf_Utf8(Document document, PdfWriter writer, String html) 
{
    XMLWorkerHelper xml = XMLWorkerHelper.GetInstance();
    xml.ParseXHtml(writer, document, stringToStream(html), System.Text.Encoding.UTF8);
}
public Stream stringToStream(string txt) {
    var stream = new MemoryStream();
    var w = new StreamWriter(stream);
    w.Write(txt);
    w.Flush();
    stream.Position = 0;
    return stream;
}
0
Pablo G. González