Как конвертировать HTML в PDF с помощью iTextSharp


Я хочу конвертировать приведенный ниже HTML в PDF с помощью iTextSharp, но не знаю, с чего начать:

<style>
.headline{font-size:200%}
</style>
<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>
5 55

5 ответов:

во-первых, HTML и PDF не связаны, хотя они были созданы примерно в то же время. HTML предназначен для передачи информации более высокого уровня, такой как абзацы и таблицы. Хотя есть методы для управления им, это в конечном счете до браузера, чтобы нарисовать эти концепции более высокого уровня. PDF предназначен для передачи документы и документы должны "смотреть" то же самое, где они отображаются.

в HTML-документе у вас может быть абзац это 100% широкий и в зависимости от ширины вашего монитора это может занять 2 строки или 10 строк, и когда вы печатаете его это может быть 7 строк и когда вы смотрите на него на вашем телефоне это может занять 20 строк. PDF файл, однако, должно быть независимо от устройства рендеринга, так что независимо от вашего размера экрана это всегда оказывать точно такой же.

из-за Муст выше, PDF не поддерживает абстрактные вещи, такие как "таблицы" или "пункты." Есть три основные вещи, которые поддерживает PDF: текст, линии/формы и изображения. (есть и другие вещи, такие как аннотации и фильмы, но я пытаюсь сохранить его простым здесь.) в PDF вы не говорите: "вот абзац, браузер делает свое дело!". Вместо этого вы говорите: "нарисуйте этот текст в этом точном месте X, Y,используя этот точный шрифт, и не волнуйтесь, я ранее рассчитал ширину текста, поэтому я знаю, что все это будет соответствовать этой строке". Вы также не говорите: "вот стол" но вместо этого вы говорите: "нарисуйте этот текст в этом точном месте, а затем нарисуйте прямоугольник в этом другом точном месте, которое я ранее рассчитал, поэтому я знаю, что он будет отображаться вокруг текста".

во-вторых, iText и iTextSharp разбирают HTML и CSS. Вот и все. ASP.Net, MVC, Razor, Struts, Spring и т. д.-Это все HTML-фреймворки, но iText/iTextSharp на 100% не знает о них. То же самое с элементов datagridview, репитеры, шаблонов, представлений и т. д. которые являются абстракциями, специфичными для фреймворка. Это код ответственность за получение HTML из вашего выбора фреймворка, iText вам не поможет. Если вы получаете исключение, говоря The document has no pages или вы думаете ,что" iText не разбирает мой HTML " это почти определенно, что вы на самом деле неесть HTML, вы только думаете, что вы делаете.

в-третьих, встроенный класс, который был вокруг в течение многих лет является HTMLWorker однако это было заменено с XMLWorker (Java / .Сети). Нулевая работа выполняется на HTMLWorker который не поддерживает CSS файлы и имеет только ограниченную поддержку для самых основных свойств CSS и на самом деле перерывы на определенные теги. Если вы не видите HTML атрибут или CSS свойство и значение в этом файле тогда это, вероятно, не поддерживается HTMLWorker. XMLWorker может быть сложнее иногда, но эти осложнения также сделатьбольше расширяемый.

ниже приведен код C#, который показывает, как разбирать HTML-теги в абстракции iText, которые автоматически добавляются в документ, над которым вы работаете. C# и Java очень похожи, поэтому это должно быть относительно легко преобразовать. Пример №1 использует встроенный HTMLWorker для разбора HTML-строки. Поскольку поддерживаются только встроенные стили class="headline" игнорируется, но все остальное должно работать. Пример №2 такой же, как и первый, за исключением того, что он использует . Пример №3 также анализирует простой пример CSS.

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

обновление 2017 года

есть хорошие новости для требований HTML-to-PDF. Как этот ответ показал,стандарт W3C css-break-3 решит проблему... Это рекомендация кандидата с планом превратиться в окончательную рекомендацию в этом году, после испытаний.

как не-так-стандартные есть решения, с плагинами для C#, как показал print-css.скалы.

@Chris Haas очень хорошо объяснил, как использовать itextSharp преобразование HTML до PDF, очень полезно
мое добавить это:
С помощью HtmlTextWriter я помещаю html-теги внутрь HTML таблица + встроенный CSS я получил свой PDF, как я хотел без использования XMLWorker .
Edit: добавить пример кода:
ASPX страница:

<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# код:

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

конечно, включите Itextsharp Refrences в cs-файл

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

надеюсь, что это помогает!
спасибо

по состоянию на 2018 год, есть также iText7 (следующая итерация старой библиотеки iTextSharp) и ее пакет HTML в PDF доступны:itext7.pdfhtml

использование просто:

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

метод имеет гораздо больше перегрузок.

обновление: iText* семейство продуктов модель двойного лицензирования: бесплатно для открытого исходного кода, оплачивается для коммерческого использования.

Я использую следующий код для создания PDF

protected void CreatePDF(Stream stream)
        {
            using (var document = new Document(PageSize.A4, 40, 40, 40, 30))
            {
                var writer = PdfWriter.GetInstance(document, stream);
                writer.PageEvent = new ITextEvents();
                document.Open();

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

                //Register Fonts.
                XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
                fontProvider.Register(HttpContext.Current.Server.MapPath("~/Content/Fonts/GothamRounded-Medium.ttf"), "Gotham Rounded Medium");
                CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);

                var htmlPipelineContext = new HtmlPipelineContext(cssAppliers);
                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(CSSSource, "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(HTMLSource))
                {
                    parser.Parse(stringReader);
                    document.Close();
                    HttpContext.Current.Response.ContentType = "application /pdf";
                    if (base.View)
                        HttpContext.Current.Response.AddHeader("content-disposition", "inline;filename=\"" + OutputFileName + ".pdf\"");
                    else
                        HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=\"" + OutputFileName + ".pdf\"");
                    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
                    HttpContext.Current.Response.WriteFile(OutputPath);
                    HttpContext.Current.Response.End();
                }
            }
        }

вот ссылка, которую я использовал в качестве руководства. Надеюсь, это поможет!

преобразование HTML в PDF с помощью ITextSharp

protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            string strHtml = string.Empty;
            //HTML File path -http://aspnettutorialonline.blogspot.com/
            string htmlFileName = Server.MapPath("~") + "\files\" + "ConvertHTMLToPDF.htm";
            //pdf file path. -http://aspnettutorialonline.blogspot.com/
            string pdfFileName = Request.PhysicalApplicationPath + "\files\" + "ConvertHTMLToPDF.pdf";

            //reading html code from html file
            FileStream fsHTMLDocument = new FileStream(htmlFileName, FileMode.Open, FileAccess.Read);
            StreamReader srHTMLDocument = new StreamReader(fsHTMLDocument);
            strHtml = srHTMLDocument.ReadToEnd();
            srHTMLDocument.Close();

            strHtml = strHtml.Replace("\r\n", "");
            strHtml = strHtml.Replace("", "");

            CreatePDFFromHTMLFile(strHtml, pdfFileName);

            Response.Write("pdf creation successfully with password -http://aspnettutorialonline.blogspot.com/");
        }
        catch (Exception ex)
        {
            Response.Write(ex.Message);
        }
    }
    public void CreatePDFFromHTMLFile(string HtmlStream, string FileName)
    {
        try
        {
            object TargetFile = FileName;
            string ModifiedFileName = string.Empty;
            string FinalFileName = string.Empty;

            /* To add a Password to PDF -http://aspnettutorialonline.blogspot.com/ */
            TestPDF.HtmlToPdfBuilder builder = new TestPDF.HtmlToPdfBuilder(iTextSharp.text.PageSize.A4);
            TestPDF.HtmlPdfPage first = builder.AddPage();
            first.AppendHtml(HtmlStream);
            byte[] file = builder.RenderPdf();
            File.WriteAllBytes(TargetFile.ToString(), file);

            iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader(TargetFile.ToString());
            ModifiedFileName = TargetFile.ToString();
            ModifiedFileName = ModifiedFileName.Insert(ModifiedFileName.Length - 4, "1");

            string password = "password";
            iTextSharp.text.pdf.PdfEncryptor.Encrypt(reader, new FileStream(ModifiedFileName, FileMode.Append), iTextSharp.text.pdf.PdfWriter.STRENGTH128BITS, password, "", iTextSharp.text.pdf.PdfWriter.AllowPrinting);
            //http://aspnettutorialonline.blogspot.com/
            reader.Close();
            if (File.Exists(TargetFile.ToString()))
                File.Delete(TargetFile.ToString());
            FinalFileName = ModifiedFileName.Remove(ModifiedFileName.Length - 5, 1);
            File.Copy(ModifiedFileName, FinalFileName);
            if (File.Exists(ModifiedFileName))
                File.Delete(ModifiedFileName);

        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

вы можете скачать файл-образец. Просто поместите html вы хотите конвертировать в files папка и запуск. Он будет автоматически генерировать pdf-файл и поместить его в ту же папку. Но в вашем случае вы можете указать свой html-путь в htmlFileName переменной.