So konvertieren Sie HTML in PDF mit iTextSharp

 C Programming >> C-Programmierung >  >> Tags >> PDF
So konvertieren Sie HTML in PDF mit iTextSharp

Erstens sind HTML und PDF nicht verwandt, obwohl sie ungefähr zur gleichen Zeit erstellt wurden. HTML soll Informationen auf höherer Ebene wie Absätze und Tabellen vermitteln. Obwohl es Methoden gibt, um es zu kontrollieren, ist es letztendlich Sache des Browsers, diese übergeordneten Konzepte zu zeichnen. PDF soll Dokumente vermitteln und die Dokumente müssen "sehen" überall gleich aus, wo sie gerendert werden.

In einem HTML-Dokument haben Sie möglicherweise einen Absatz, der 100 % breit ist, und abhängig von der Breite Ihres Monitors kann er 2 oder 10 Zeilen umfassen, und wenn Sie ihn drucken, können es 7 Zeilen sein, und wenn Sie ihn auf Ihrem Telefon betrachten, sind es möglicherweise Nimm 20 Zeilen. Eine PDF-Datei muss jedoch sein unabhängig vom Wiedergabegerät, also unabhängig von Ihrer Bildschirmgröße immer genau gleich rendern.

Wegen der Muss oben unterstützt PDF keine abstrakten Dinge wie "Tabellen" oder "Absätze". Es gibt drei grundlegende Dinge, die PDF unterstützt:Text, Linien/Formen und Bilder. (Es gibt andere Dinge wie Anmerkungen und Filme, aber ich versuche es hier einfach zu halten.) In einem PDF sagt man nicht "Hier ist ein Absatz, Browser mach dein Ding!". Stattdessen sagen Sie:"Zeichnen Sie diesen Text genau an dieser X-, Y-Position mit genau dieser Schriftart und machen Sie sich keine Sorgen, ich habe die Breite des Textes zuvor berechnet, damit ich weiß, dass alles in diese Zeile passt." Sie sagen auch nicht "hier ist eine Tabelle", sondern sagen stattdessen "zeichne diesen Text genau an dieser Stelle und zeichne dann ein Rechteck an dieser anderen genauen Stelle, die ich zuvor berechnet habe, damit ich weiß, dass es um den Text herum zu sein scheint ".

Zweitens parsen iText und iTextSharp HTML und CSS. Das ist es. ASP.Net, MVC, Razor, Struts, Spring usw. sind allesamt HTML-Frameworks, aber iText/iTextSharp kennt sie zu 100 % nicht. Gleiches gilt für DataGridViews, Repeater, Templates, Views usw., die alle Framework-spezifische Abstraktionen sind. Es ist dein dafür verantwortlich sind, den HTML-Code von dem Framework Ihrer Wahl zu erhalten, wird iText Ihnen nicht helfen. Wenn Sie eine Ausnahme erhalten, die besagt:The document has no pages oder Sie denken, dass "iText meinen HTML-Code nicht analysiert", ist es fast sicher, dass Sie tatsächlich keinen HTML-Code haben, Sie glauben nur, dass Sie ihn haben.

Drittens ist die eingebaute Klasse, die es seit Jahren gibt, die HTMLWorker dies wurde jedoch durch XMLWorker ersetzt (Java/.Net). An HTMLWorker wird null Arbeit geleistet das keine CSS-Dateien unterstützt und nur begrenzte Unterstützung für die grundlegendsten CSS-Eigenschaften bietet und bei bestimmten Tags tatsächlich bricht. Wenn Sie das HTML-Attribut oder die CSS-Eigenschaft und den Wert in dieser Datei nicht sehen, wird es wahrscheinlich nicht von HTMLWorker unterstützt . XMLWorker kann manchmal komplizierter sein, aber diese Komplikationen machen es auch erweiterbarer.

Unten ist C#-Code, der zeigt, wie HTML-Tags in iText-Abstraktionen geparst werden, die automatisch dem Dokument hinzugefügt werden, an dem Sie arbeiten. C# und Java sind sich sehr ähnlich, daher sollte es relativ einfach sein, dies zu konvertieren. Beispiel #1 verwendet den eingebauten HTMLWorker um den HTML-String zu parsen. Da nur Inline-Stile unterstützt werden, ist class="headline" wird ignoriert, aber alles andere sollte eigentlich funktionieren. Beispiel #2 ist das gleiche wie das erste, außer dass es XMLWorker verwendet stattdessen. Beispiel #3 analysiert auch das einfache CSS-Beispiel.

//Create a byte array that will eventually hold our final PDF
Byte[] bytes;

//Boilerplate iTextSharp setup here
//Create a stream that we can write to, in this case a MemoryStream
using (var ms = new MemoryStream()) {

    //Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
    using (var doc = new Document()) {

        //Create a writer that's bound to our PDF abstraction and our stream
        using (var writer = PdfWriter.GetInstance(doc, ms)) {

            //Open the document for writing
            doc.Open();

            //Our sample HTML and CSS
            var example_html = @"<p>This <em>is </em><span class=""headline"" style=""text-decoration: underline;"">some</span> <strong>sample <em> text</em></strong><span style=""color: red;"">!!!</span></p>";
            var example_css = @".headline{font-size:200%}";

            /**************************************************
             * Example #1                                     *
             *                                                *
             * Use the built-in HTMLWorker to parse the HTML. *
             * Only inline CSS is supported.                  *
             * ************************************************/

            //Create a new HTMLWorker bound to our document
            using (var htmlWorker = new iTextSharp.text.html.simpleparser.HTMLWorker(doc)) {

                //HTMLWorker doesn't read a string directly but instead needs a TextReader (which StringReader subclasses)
                using (var sr = new StringReader(example_html)) {

                    //Parse the HTML
                    htmlWorker.Parse(sr);
                }
            }

            /**************************************************
             * Example #2                                     *
             *                                                *
             * Use the XMLWorker to parse the HTML.           *
             * Only inline CSS and absolutely linked          *
             * CSS is supported                               *
             * ************************************************/

            //XMLWorker also reads from a TextReader and not directly from a string
            using (var srHtml = new StringReader(example_html)) {

                //Parse the HTML
                iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
            }

            /**************************************************
             * Example #3                                     *
             *                                                *
             * Use the XMLWorker to parse HTML and CSS        *
             * ************************************************/

            //In order to read CSS as a string we need to switch to a different constructor
            //that takes Streams instead of TextReaders.
            //Below we convert the strings into UTF8 byte array and wrap those in MemoryStreams
            using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_css))) {
                using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_html))) {

                    //Parse the HTML
                    iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHtml, msCss);
                }
            }


            doc.Close();
        }
    }

    //After all of the PDF "stuff" above is done and closed but **before** we
    //close the MemoryStream, grab all of the active bytes from the stream
    bytes = ms.ToArray();
}

//Now we just need to do something with those bytes.
//Here I'm writing them to disk but if you were in ASP.Net you might Response.BinaryWrite() them.
//You could also write the bytes to a database in a varbinary() column (but please don't) or you
//could pass them to another function for further PDF processing.
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
System.IO.File.WriteAllBytes(testFile, bytes);

Aktualisierung 2017

Es gibt gute Nachrichten für HTML-zu-PDF-Anforderungen. Wie diese Antwort zeigte, wird der W3C-Standard css-break-3 das Problem lösen ... Es handelt sich um eine Kandidatenempfehlung, die nach Tests dieses Jahr in eine endgültige Empfehlung umgewandelt werden soll.

Als Nicht-Standard gibt es Lösungen mit Plugins für C#, wie print-css.rocks zeigt.


Ab 2018 gibt es auch iText7 (Eine nächste Iteration der alten iTextSharp-Bibliothek) und ihr HTML-zu-PDF-Paket verfügbar:itext7.pdfhtml

Die Verwendung ist einfach:

HtmlConverter.ConvertToPdf(
    new FileInfo(@"Path\to\Html\File.html"),
    new FileInfo(@"Path\to\Pdf\File.pdf")
);

Die Methode hat viel mehr Überladungen.

Aktualisierung: Die iText*-Produktfamilie hat ein duales Lizenzmodell:kostenlos für Open Source, kostenpflichtig für die kommerzielle Nutzung.


@Chris Haas hat sehr gut erklärt, wie man itextSharp verwendet um HTML umzuwandeln bis PDF , sehr hilfreich
mein add ist:
Durch die Verwendung von HtmlTextWriter Ich habe HTML-Tags in HTML eingefügt Tabelle + Inline-CSS Ich habe mein PDF so bekommen, wie ich es wollte, ohne XMLWorker zu verwenden .
Bearbeiten :Beispielcode hinzufügen:
ASPX-Seite:

<asp:Panel runat="server" ID="PendingOrdersPanel">
 <!-- to be shown on PDF-->
 <table style="border-spacing: 0;border-collapse: collapse;width:100%;display:none;" >
 <tr><td><img src="abc.com/webimages/logo1.png" style="display: none;" width="230" /></td></tr>
<tr style="line-height:10px;height:10px;"><td style="display:none;font-size:9px;color:#10466E;padding:0px;text-align:right;">blablabla.</td></tr>
 <tr style="line-height:10px;height:10px;"><td style="display:none;font-size:9px;color:#10466E;padding:0px;text-align:right;">blablabla.</td></tr>
 <tr style="line-height:10px;height:10px;"><td style="display:none;font-size:9px;color:#10466E;padding:0px;text-align:right;">blablabla</td></tr>
<tr style="line-height:10px;height:10px;"><td style="display:none;font-size:9px;color:#10466E;padding:0px;text-align:right;">blablabla</td></tr>
<tr style="line-height:10px;height:10px;"><td style="display:none;font-size:11px;color:#10466E;padding:0px;text-align:center;"><i>blablabla</i> Pending orders report<br /></td></tr>
 </table>
<asp:GridView runat="server" ID="PendingOrdersGV" RowStyle-Wrap="false" AllowPaging="true" PageSize="10" Width="100%" CssClass="Grid" AlternatingRowStyle-CssClass="alt" AutoGenerateColumns="false"
   PagerStyle-CssClass="pgr" HeaderStyle-ForeColor="White" PagerStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="Center" RowStyle-HorizontalAlign="Center" DataKeyNames="Document#" 
      OnPageIndexChanging="PendingOrdersGV_PageIndexChanging" OnRowDataBound="PendingOrdersGV_RowDataBound" OnRowCommand="PendingOrdersGV_RowCommand">
   <EmptyDataTemplate><div style="text-align:center;">no records found</div></EmptyDataTemplate>
    <Columns>                                           
     <asp:ButtonField CommandName="PendingOrders_Details" DataTextField="Document#" HeaderText="Document #" SortExpression="Document#" ItemStyle-ForeColor="Black" ItemStyle-Font-Underline="true"/>
      <asp:BoundField DataField="Order#" HeaderText="order #" SortExpression="Order#"/>
     <asp:BoundField DataField="Order Date" HeaderText="Order Date" SortExpression="Order Date" DataFormatString="{0:d}"></asp:BoundField> 
    <asp:BoundField DataField="Status" HeaderText="Status" SortExpression="Status"></asp:BoundField>
    <asp:BoundField DataField="Amount" HeaderText="Amount" SortExpression="Amount" DataFormatString="{0:C2}"></asp:BoundField> 
   </Columns>
    </asp:GridView>
</asp:Panel>

C#-Code:

protected void PendingOrdersPDF_Click(object sender, EventArgs e)
{
    if (PendingOrdersGV.Rows.Count > 0)
    {
        //to allow paging=false & change style.
        PendingOrdersGV.HeaderStyle.ForeColor = System.Drawing.Color.Black;
        PendingOrdersGV.BorderColor = Color.Gray;
        PendingOrdersGV.Font.Name = "Tahoma";
        PendingOrdersGV.DataSource = clsBP.get_PendingOrders(lbl_BP_Id.Text);
        PendingOrdersGV.AllowPaging = false;
        PendingOrdersGV.Columns[0].Visible = false; //export won't work if there's a link in the gridview
        PendingOrdersGV.DataBind();

        //to PDF code --Sam
        string attachment = "attachment; filename=report.pdf";
        Response.ClearContent();
        Response.AddHeader("content-disposition", attachment);
        Response.ContentType = "application/pdf";
        StringWriter stw = new StringWriter();
        HtmlTextWriter htextw = new HtmlTextWriter(stw);
        htextw.AddStyleAttribute("font-size", "8pt");
        htextw.AddStyleAttribute("color", "Grey");

        PendingOrdersPanel.RenderControl(htextw); //Name of the Panel
        Document document = new Document();
        document = new Document(PageSize.A4, 5, 5, 15, 5);
        FontFactory.GetFont("Tahoma", 50, iTextSharp.text.BaseColor.BLUE);
        PdfWriter.GetInstance(document, Response.OutputStream);
        document.Open();

        StringReader str = new StringReader(stw.ToString());
        HTMLWorker htmlworker = new HTMLWorker(document);
        htmlworker.Parse(str);

        document.Close();
        Response.Write(document);
    }
}

natürlich iTextSharp-Referenzen in die cs-Datei einfügen

using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.html.simpleparser;
using iTextSharp.tool.xml;

Hoffe das hilft!
Vielen Dank