Подтвердить что ты не робот

Как конвертировать 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>
4b9b3361

Ответ 1

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

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

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

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

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

Ниже приведен код С#, в котором показано, как анализировать теги HTML в текстовых абстракциях, которые автоматически добавляются в документ, над которым вы работаете. С# и Java очень похожи, поэтому относительно легко их конвертировать. В примере # 1 используется встроенный HTMLWorker для синтаксического анализа строки HTML. Поскольку поддерживаются только встроенные стили, class="headline" игнорируется, но все остальное должно работать. Пример # 2 совпадает с первым, за исключением того, что вместо него используется XMLWorker. Пример # 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 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 разрешит проблема... Это рекомендация кандидата с планом превратиться в окончательную рекомендацию в этом году после тестов.

В качестве нестандартного решения существуют решения с плагинами для С#, как показано print-css.rocks.

Ответ 2

@Крис Хаас очень хорошо объяснил, как использовать itextSharp для преобразования HTML в PDF, очень полезно
мое добавление:
Используя HtmlTextWriter, я помещаю html-теги внутри HTML table + inline CSS, я получил свой PDF файл, как я хотел, без использования XMLWorker.
Изменить: добавление образца кода:
Страница 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>

Код С#:

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

Надеюсь, это поможет!
Спасибо

Ответ 3

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

Преобразование 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("\0", "");

            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.