iTextSharp HTMLWorker ParseHTML Tablestyle и PDFStamper - PullRequest
2 голосов
/ 07 декабря 2011

Привет! Я успешно использовал HTMLWorker для преобразования вида сетки с использованием asp.NET / C #.

(1) Я применил некоторый ограниченный стиль к результирующей таблице, но не вижу, как применить стиль таблицы для линий сетки экземпляра или применить другой стиль форматирования, например большую ширину столбца, например, для определенного столбца. (2) Я бы хотел поместить этот текст в уже существующий шаблон, содержащий логотип и т. Д. Я использовал для этого PDF Stamper, но не могу понять, как я могу одновременно использовать PDFStamper и HTMLWorker. HTMLWorker нужен документ, который реализует iDocListener ... но он не кажется совместимым с использованием PDFStamper. Я думаю, что я ищу способ создать PDFStamper, написать заголовок и т. Д., А затем добавить проанализированный HTML из сетки. Другая проблема заключается в том, что проанализированный контент не взаимодействует с другими материалами на странице. Например, ниже я добавляю блок заголовка на страницу. Вместо того, чтобы начинать с него, проанализированный HTML записывает поверх. Как разместить / взаимодействовать проанализированный HTML-контент с остальным содержимым PDF-документа?

Спасибо заранее Rob

Вот код, который у меня уже есть

            Document pdfDoc = new Document(PageSize.A4, 10f, 10f, 30f, 0f);

            HTMLWorker htmlWorker = new HTMLWorker(pdfDoc);

            StyleSheet styles = new StyleSheet();
            styles.LoadTagStyle("th", "size", "12px");
            styles.LoadTagStyle("th", "face", "helvetica");
            styles.LoadTagStyle("span", "size", "10px");
            styles.LoadTagStyle("span", "face", "helvetica");                
            styles.LoadTagStyle("td", "size", "10px");
            styles.LoadTagStyle("td", "face", "helvetica");     

            htmlWorker.SetStyleSheet(styles);

            PdfWriter.GetInstance(pdfDoc, HttpContext.Current.Response.OutputStream);

            pdfDoc.Open();

            //Title - but this gets obsured by data, doesnt move it down
            Font font = new Font(Font.FontFamily.HELVETICA, 14, Font.BOLD);
            Chunk chunk = new Chunk(title, font);                
            pdfDoc.Add(chunk);


            //Body
            htmlWorker.Parse(sr);

Ответы [ 2 ]

12 голосов
/ 07 декабря 2011

Позвольте мне сначала дать вам пару ссылок для просмотра, когда у вас есть шанс:

  1. Поддержка ItextSharp для HTML и CSS
  2. Как применить свойства шрифта при передаче html в pdf, используя itextsharp

Эти ответы углубляются в то, что происходит, и я рекомендую прочитать их, когда у вас будет возможность. В частности, второй покажет вам, почему вам нужно использовать pt вместо px.

Чтобы ответить на ваш первый вопрос, позвольте мне показать вам другой способ использования класса HTMLWorker. Этот класс имеет статический метод с именем ParseToList, который преобразует HTML в List<IElement>. Все объекты в этом списке являются специфическими версиями вашего HTML для iTextSharp. Обычно вы делаете foreach для них и просто добавляете их в документ, но вы можете изменить их перед добавлением, что вы и хотите сделать. Ниже приведен код, который принимает статическую строку и делает это:

string file1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "File1.pdf");

using (FileStream fs = new FileStream(file1, FileMode.Create, FileAccess.Write, FileShare.None))
{
    using (Document doc = new Document(PageSize.LETTER))
    {
        using (PdfWriter writer = PdfWriter.GetInstance(doc, fs))
        {
            doc.Open();
            //Our HTML
            string html = "<table><tr><th>First Name</th><th>Last Name</th></tr><tr><td>Chris</td><td>Haas</td></tr></table>";
            //ParseToList requires a StreamReader instead of just a string so just wrap it
            using (StringReader sr = new StringReader(html))
            {
                //Create a style sheet
                StyleSheet styles = new StyleSheet();
                //...styles omitted for brevity

                //Convert our HTML to iTextSharp elements
                List<IElement> elements = iTextSharp.text.html.simpleparser.HTMLWorker.ParseToList(sr, styles);
                //Loop through each element (in this case there's actually just one PdfPTable)
                foreach (IElement el in elements)
                {
                    //If the element is a PdfPTable
                    if (el is PdfPTable)
                    {
                        //Cast it
                        PdfPTable tt = (PdfPTable)el;
                        //Change the widths, these are relative width by the way
                        tt.SetWidths(new float[] { 75, 25 });
                    }
                    //Add the element to the document
                    doc.Add(el);
                }
            }
            doc.Close();
        }
    }
}

Надеюсь, вы увидите, что как только вы получите доступ к необработанному PdfPTable, вы сможете настроить его по мере необходимости.

Чтобы ответить на ваш второй вопрос, если вы хотите использовать обычные Paragraph и Chunk объекты с PdfStamper, тогда вам нужно использовать PdfContentByte объект. Вы можете получить это из вашего штампа одним из двух способов, либо запросив тот, который находится «над» существующим контентом, stamper.GetOverContent(int), либо тот, который находится «под» существующим контентом, stamper.GetUnderContent(int). Обе версии принимают один параметр, указывающий, с какой страницей работать. Если у вас есть PdfContentByte, вы можете создать связанный с ним объект ColumnText и использовать метод AddElement() этого объекта для добавления ваших обычных элементов. Прежде чем сделать это (и это ответит на ваш третий вопрос), вам нужно создать хотя бы одну «колонку». Когда я делаю это, я обычно создаю тот, который по существу покрывает всю страницу. (Эта часть может показаться странной, но мы, по сути, делаем одну строку, ячейку таблицы из одного столбца, к которой добавляем наши объекты.)

Ниже представлено полнофункциональное приложение WinForms для C # 2010, предназначенное для iTextSharp 5.1.1.0, которое демонстрирует все вышеперечисленное. Сначала он создает общий PDF на рабочем столе. Затем он создает второй документ на основе первого, добавляет абзац, а затем немного HTML. Смотрите комментарии в коде по любым вопросам.

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
using System.IO;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //The two files that we are creating
            string file1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "File1.pdf");
            string file2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "File2.pdf");

            //Create a base file to write on top of
            using (FileStream fs = new FileStream(file1, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                using (Document doc = new Document(PageSize.LETTER))
                {
                    using (PdfWriter writer = PdfWriter.GetInstance(doc, fs))
                    {
                        doc.Open();
                        doc.Add(new Paragraph("Hello world"));
                        doc.Close();
                    }
                }
            }

            //Bind a reader to our first document
            PdfReader reader = new PdfReader(file1);

            //Create our second document
            using (FileStream fs = new FileStream(file2, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                using (PdfStamper stamper = new PdfStamper(reader, fs))
                {
                    StyleSheet styles = new StyleSheet();
                    //...styles omitted for brevity

                    //Our HTML
                    string html = "<table><tr><th>First Name</th><th>Last Name</th></tr><tr><td>Chris</td><td>Haas</td></tr></table>";
                    //ParseToList requires a StreamReader instead of just a string so just wrap it
                    using (StringReader sr = new StringReader(html))
                    {
                        //Get our raw PdfContentByte object letting us draw "above" existing content
                        PdfContentByte cb = stamper.GetOverContent(1);
                        //Create a new ColumnText object bound to the above PdfContentByte object
                        ColumnText ct = new ColumnText(cb);
                        //Get the dimensions of the first page of our source document
                        iTextSharp.text.Rectangle page1size = reader.GetPageSize(1);
                        //Create a single column object spanning the entire page
                        ct.SetSimpleColumn(0, 0, page1size.Width, page1size.Height);

                        ct.AddElement(new Paragraph("Hello world!"));

                        //Convert our HTML to iTextSharp elements
                        List<IElement> elements = iTextSharp.text.html.simpleparser.HTMLWorker.ParseToList(sr, styles);
                        //Loop through each element (in this case there's actually just one PdfPTable)
                        foreach (IElement el in elements)
                        {
                            //If the element is a PdfPTable
                            if (el is PdfPTable)
                            {
                                //Cast it
                                PdfPTable tt = (PdfPTable)el;
                                //Change the widths, these are relative width by the way
                                tt.SetWidths(new float[] { 75, 25 });
                            }
                            //Add the element to the ColumnText
                            ct.AddElement(el);
                        }
                        //IMPORTANT, this actually commits our object to the PDF
                        ct.Go();
                    }
                }
            }

            this.Close();
        }
    }
}
0 голосов
/ 28 марта 2012
protected void LinkPdf_Click(object sender, EventArgs e)
{
    Response.ContentType = "application/pdf";
    Response.AddHeader("content-disposition", "attachment;filename=TestPage.pdf");
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    StringWriter sw = new StringWriter();
    HtmlTextWriter hw = new HtmlTextWriter(sw);
    this.Page.RenderControl(hw);
    StringReader sr = new StringReader(sw.ToString());
    Document pdfDoc = new Document(PageSize.A4, 10f, 10f, 100f, 0f);
    HTMLWorker htmlparser = new HTMLWorker(pdfDoc);
    PdfWriter.GetInstance(pdfDoc, Response.OutputStream);
    pdfDoc.Open();
    htmlparser.Parse(sr);
    pdfDoc.Close();
    Response.Write(pdfDoc);
    Response.End();
}
...