2016-03-23 20 views
8

È possibile ottenere la direzione di scrittura del testo dal basso verso l'alto in xmlworker? Mi piacerebbe usarlo in tavola. mio codice èUtilizzare itextsharp xmlworker per convertire HTML in PDF e scrivere il testo verticalmente

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

Ma non funziona dopo la conversione da HTML a PDF. Il testo FIRST e SECOND non sono in direzione dal basso verso l'alto.

+0

È necessario scrivere codice personalizzato per fare questo. Se aggiungi un esempio HTML di ciò che ti aspetti, qualcuno può aiutare ... – kuujinbo

risposta

6

Questo era un problema piuttosto interessante, quindi +1 alla domanda.

Il primo passo è stato cercare se iTextSharp XML Worker supporta o meno il tag HTMLtd. Le mappature possono essere trovate nella fonte in iTextSharp.tool.xml.html.Tags. Qui trovi che td è mappato a iTextSharp.tool.xml.html.table.TableData, il che rende un po 'più semplice l'implementazione di un processore di tag personalizzato. Cioè tutto quello che dobbiamo fare ereditare dalla classe ed eseguire l'override 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; 
    } 
} 

Come notato nei commenti in linea, questo è un molto semplice implementazione per le vostre esigenze specifiche. È necessario aggiungere una logica aggiuntiva per supportare qualsiasi altro writing-modeCSS property value e includere qualsiasi controllo di integrità.

UPDATE

Basato sul commento lasciato da @Daniel, non è chiaro come aggiungere personalizzato CSS durante la conversione del HTML-PDF. In primo luogo il codice HTML aggiornamento:

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

Poi un piccolo frammento di CSS personalizzato:

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 parte un po 'difficile è la messa a punto in più - non è possibile utilizzare la semplice fuori dalla scatola XMLWorkerHelper.GetInstance().ParseXHtml() comunemente visto qui a SO. Ecco un metodo di supporto semplice che dovrebbe iniziare:

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

Invece di rimasticare una spiegazione del codice di esempio precedente, see the documentation (iText rimosso la documentazione, legato alla Wayback Machine) per avere una migliore idea del motivo per cui è necessario imposta il parser in questo modo.

Si noti inoltre:

  1. Worker XML non lo fa sostegno tutte le proprietà CSS2/CSS3, in modo da può necessità di sperimentare ciò che funziona o non funziona per quanto riguarda quanto vicino si desidera che il PDF per guardare l'HTML visualizzato nel browser.
  2. Lo snippet HTML ha rimosso il tag p, poiché lo stile può essere applicato direttamente al tag td.
  3. La proprietà in linea width. Se omesso, le colonne avranno ampiezze variabili che corrispondono se il testo è stato reso in orizzontale.

Testato con le versioni di iTextSharp e XML Worker 5.5.9 Ecco il risultato aggiornato:

enter image description here

+0

Grazie mille. È molto utile Nel mio caso il file html è grande. Ci sono molti tavoli ma solo due tabelle hanno bisogno di testo verticale. Mi chiedo come implementare il resto del codice del mio css. L'ho fatto prima: 'using (var myCss = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (example_css))) { utilizzando (var msHtml = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (example_html))) {iTextSharp.tool.xml.XMLWorkerHelper.GetInstance(). ParseXHtml (writer, doc, msHtml, myCss); } } ' – Daniel

+0

@Daniel - ha aggiornato la risposta per includere un metodo di supporto che consente di passare una stringa' HTML' e una stringa 'CSS'. – kuujinbo

+0

Ancora una volta, grazie mille. – Daniel

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

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