2016-03-23 23 views
8

Czy jest możliwe osiągnięcie tekstu w kierunku od dołu do góry w xmlworker? Chciałbym go użyć w tabeli. Mój kod jestUżywanie itextsharp xmlworker do konwersji html na pdf i pisania tekstu w pionie

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

Ale to nie działa po konwersji z HTML do PDF. Tekst FIRST i SECOND nie są skierowane od dołu do góry.

+0

Musisz napisać niestandardowy kod, aby to zrobić. Jeśli dodasz 'HTML'przykład tego, czego oczekujesz, ktoś _może_ będzie w stanie pomóc ... – kuujinbo

Odpowiedz

6

To był całkiem interesujący problem, więc +1 na pytanie.

Pierwszym krokiem było sprawdzenie, czy iTextSharp XML Worker obsługuje znacznik HTMLtd. Mapowania można znaleźć w źródle w iTextSharp.tool.xml.html.Tags. Tam znajduje się td jest zmapowany do iTextSharp.tool.xml.html.table.TableData, co sprawia, że ​​zadanie zaimplementowania niestandardowego procesora tagów jest nieco łatwiejsze. To znaczy. wszyscy musimy dziedziczą z klasy i zastąpić 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; 
    } 
} 

Jak zauważono w inline komentarze, to bardzo prosta implementacja do konkretnych potrzeb. Musisz dodać dodatkową logikę, aby obsłużyć każdy inny numer writing-modeCSS property value i uwzględnić wszystkie testy poprawności.

UPDATE

oparciu o komentarz pozostawiony przez @Daniel, to nie jest jasne, w jaki sposób dodać niestandardową CSS przy przeliczaniu HTML do PDF. Pierwszy zaktualizowany HTML:

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

Następnie mały fragment niestandardowego CSS:

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

Nieco trudniejsze jest to dodatkowa konfiguracja - nie można używać prostych wyjęciu z pudełka XMLWorkerHelper.GetInstance().ParseXHtml() powszechnie postrzegane tutaj w SO. Oto prosty sposób pomocnikiem, który powinien Ci zacząć:

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

Zamiast hashuje wyjaśnienie kodu powyższym przykładzie see the documentation (iText usunięto dokumentację, związaną z Wayback Machine), aby uzyskać lepsze wyobrażenie o tym, dlaczego trzeba tak skonfigurować parser.

pamiętać również:

  1. XML Pracownik nie wsparcie wszystkich właściwości CSS2/CSS3, więc może potrzeba eksperymentowania z co działa lub nie działa w odniesieniu do tego, jak blisko chcesz PDF, aby wyświetlić kod HTML wyświetlany w przeglądarce.
  2. Fragment HTML usunął tag p, ponieważ styl można zastosować bezpośrednio do znacznika td.
  3. Własna właściwość width. Jeśli zostanie pominięty, kolumny będą miały zmienne szerokości, które pasują, jeśli tekst został renderowany w poziomie.

Testowane przy pomocy iTextSharp i wersji XML Worker 5.5.9 Oto aktualizowane wynik:

enter image description here

+0

Wielkie dzięki. Jest bardzo pomocny. W moim przypadku plik html jest duży. Istnieje wiele tabel, ale tylko dwie tablice wymagają tekstu w pionie Zastanawiam się, jak zaimplementować w kodzie resztę własnego css. Zrobiłem to wcześniej: 'using (var myCss = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (example_css))) { przy użyciu (var msHtml = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (example_html))) {iTextSharp.tool.xml.XMLWorkerHelper.GetInstance() .ParsseXHtml (pisarz, doc, msHtml, myCss); } } ' – Daniel

+0

@Daniel - zaktualizowano odpowiedź tak, aby zawierała metodę pomocniczą, która pozwala ci przekazać ciąg znaków" HTML "i ciąg znaków" CSS ". – kuujinbo

+0

Jeszcze raz dziękuję. – 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); 
} 

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