C# Json data to DataTable and generate PDF online download–iTextSharp generates PDF instance (file download, json data conversion, PDF typesetting in one step)

Foreword

This article will focus on the use of iTextSharp and some pitfalls that are easy to step on. By the way, it will introduce the simple, fast and efficient method of converting json to DataTable and the method of online instant download of binary stream conversion files. After testing, it only takes 1 second to generate a 40-page pdf, and the size does not exceed 200k. The performance and compression ratio are relatively good.

Recently, I received a request to export the front-end table data in the form of PDF. Plugins used:

  • Newtonsoft.Json
  • iTextSharp

The above plug-ins can be downloaded and referenced in nuget

1. json to DataTable

The front-end table is as follows:

The front-end json data structure is as follows:


Description: Hearder is an array, which contains the parameters of each column, such as column width, whether to hide columns (hidden columns are not exported), etc.; DataList is an array, which stores table data; Title stores the name of the table

1. Define the receiving class

First introduce Newtonsoft.Json, the purpose is to convert the json data from the front end into DataTable.
This article uses DeserializeObject(string str), which is to deserialize JSON into an object, where T is the type of object to be deserialized, and the parameter str is the JSON to be deserialized string.
After understanding the above methods, we first define the object type JsonObj of T according to the above Json format, the code is as follows:

class JsonObj
        {<!-- -->
            public DataTable Header {<!-- --> get; set; }
            public DataTable DataList {<!-- --> get; set; }
            public string Title {<!-- --> get; set; }
            public string Code {<!-- --> get; set; }
        }

2. Convert json

Then use the JsonConvert.DeserializeObject(string str) method to convert, the code is as follows:

JsonObj jsonObj = JsonConvert. DeserializeObject<JsonObj>(jsonText);

3. Complete code

using System. Data;
using Newtonsoft.Json;
using SIE.Common.Helper.Tools;
using Newtonsoft.Json.Linq;

namespace SIE.Common.Web.Helper.File
{
    /// 
    /// File export--Word, Pdf
    /// 
    public class FileExport
    {

        /// 
        /// json data processing
        /// 
        /// 
        public static string JsonToDataTable(string jsonText)
        {
            JsonObj jsonObj = JsonConvert. DeserializeObject<JsonObj>(jsonText);
            
            DataTable headerDt = jsonObj.Header;
            DataTable dataDt = jsonObj. DataList;
            string title = jsonObj.Title;
            //Call the method ExportPDF in the second section
            return ConvertPdf. ExportPDF(headerDt, dataDt, title);
        }


        class JsonObj
        {
            public DataTable Header { get; set; }
            public DataTable DataList { get; set; }
            public string Title { get; set; }
        }
    }
}

2. DataTable to PDF

In this step, I used iTextSharp. This plug-in corresponds to the Java version of iText, which is open source and free. In fact, in the process of my actual measurement, iTextSharp has powerful PDF operation capabilities, and is also capable of some complex typesetting. Its typesetting statements are similar to CSS typesetting. I use iTextSharp version 5.5. A few things to note are:

1. PDF header and footer:

Most pdf files have headers and footers. The pdf generated by iTextSharp has no headers and footers by default. We can rewrite PdfPageEventHelper to customize the settings. After rewriting OnStartPage method sets the header, rewrites the OnEndPage method to set the footer, the code is as follows:

/// <summary>
    /// Inherit PdfPageEventHelper, rewrite header and footer
    /// </summary>
    public class ItextPdfHeaderFooter : PdfPageEventHelper
    {<!-- -->
        PdfContentByte cb;
        PdfTemplate template;
        // Chinese font
        BaseFont bf = BaseFont.CreateFont(@"C:\Windows\Fonts\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        
        // Print Time
        DateTime PrintTime = DateTime. Now;
        float fontSize = 10; //font size
        float leftMargins = 14;//left margin
        float rightMargins = 14;//right margin
        float bottomMargins = 12;//bottom margin
        float topMargins = 12;//top margin

        #region header basic properties
        private string _Title;
        public string Title
        {<!-- -->
            get {<!-- --> return _Title; }
            set {<!-- --> _Title = value; }
        }
        public PdfPTable_Table;
        public PdfPTable Table
        {<!-- -->
            get {<!-- --> return _Table; }
            set {<!-- --> _Table=value; }
        }
        private string _HeaderLeft;
        public string HeaderLeft
        {<!-- -->
            get {<!-- --> return _HeaderLeft; }
            set {<!-- --> _HeaderLeft = value; }
        }
        private string _HeaderRight;
        public string HeaderRight
        {<!-- -->
            get {<!-- --> return _HeaderRight; }
            set {<!-- --> _HeaderRight = value; }
        }
        #endregion

        // Override the onOpenDocument method
        public override void OnOpenDocument(PdfWriter writer, Document document)
        {<!-- -->
            try
            {<!-- -->
                PrintTime = DateTime. Now;
                cb = writer. DirectContent;
                template = cb.CreateTemplate(50, 50);
            }
            catch (DocumentException de)
            {<!-- -->
            }
            catch (System.IO.IOException ioe)
            {<!-- -->
            }
        }
        /// <summary>
        /// Header--header
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="document"></param>
        public override void OnStartPage(PdfWriter writer, Document document)
        {<!-- -->
            base.OnStartPage(writer, document);
            Rectangle pageSize = document. PageSize;
            if (Title != null)
            {<!-- -->
                cb. BeginText();
                cb. SetFontAndSize(bf, fontSize);
                cb. SetRGBColorFill(50, 50, 200);
                cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetTop(topMargins));
                cb.ShowText(Title);
                cb. EndText();
            }
                iTextSharp.text.Font font = new Font(bf, 10, Font.NORMAL, new BaseColor(110, 84, 40));//title
                PdfPTable HeaderTable = new PdfPTable(2);
                HeaderTable.DefaultCell.VerticalAlignment = Element.ALIGN_MIDDLE;
                HeaderTable.TotalWidth = pageSize.Width - 28;
                HeaderTable.SetWidthPercentage(new float[] {<!-- --> 45, 45 }, pageSize);

                PdfPCell HeaderLeftCell = new PdfPCell(new Phrase(8, "xxxx company", font));
                HeaderLeftCell. BorderWidthLeft = 0;
                HeaderLeftCell.BorderWidthTop = 0;
                HeaderLeftCell. BorderWidthRight = 0;
                HeaderTable.AddCell(HeaderLeftCell);
                PdfPCell HeaderRightCell = new PdfPCell(new Phrase(8, "xxxx Co., Ltd", font));
                HeaderRightCell.HorizontalAlignment = PdfPCell.ALIGN_RIGHT;
                HeaderRightCell. BorderWidthLeft = 0;
            HeaderRightCell. BorderWidthRight = 0;
            HeaderRightCell.BorderWidthTop = 0;
            HeaderTable.AddCell(HeaderRightCell);
                cb. SetRGBColorFill(0, 0, 0);
                HeaderTable.WriteSelectedRows(0, -1, pageSize.GetLeft(14), pageSize.GetTop(8), cb);
        }
        /// <summary>
        /// Footer--page number
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="document"></param>
        public override void OnEndPage(PdfWriter writer, Document document)
        {<!-- -->
            base.OnEndPage(writer, document);
            int pageN = writer. PageNumber;
            String text = "第" + pageN + "page,";
            float len = bf. GetWidthPoint(text, fontSize);
            Rectangle pageSize = document. PageSize;
            cb.SetRGBColorFill(100, 100, 100);
            cb. BeginText();
            cb. SetFontAndSize(bf, fontSize);
            cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetBottom(bottomMargins));
            cb.ShowText(text);
            cb. EndText();
            cb.AddTemplate(template, pageSize.GetLeft(leftMargins) + len, pageSize.GetBottom(bottomMargins));

            cb. BeginText();
            cb. SetFontAndSize(bf, fontSize);
            cb.ShowTextAligned(PdfContentByte.ALIGN_RIGHT,
            "Generation time: " + PrintTime.ToString(),
            pageSize. GetRight(rightMargins),
            pageSize. GetBottom(bottomMargins), 0);
            cb. EndText();
        }
        public override void OnCloseDocument(PdfWriter writer, Document document)
        {<!-- -->
            base.OnCloseDocument(writer, document);
            template.BeginText();
            template. SetFontAndSize(bf, fontSize);
            template. SetTextMatrix(0, 0);
            template.ShowText("total" + (writer.PageNumber - 1) + "page");
            template. EndText();
        }
    }

The effect of the generated pdf is as follows: header and footer

2. PDF page header

When we output a table, when the table exceeds one page, iTextSharp only displays the header on the first page by default, and the other pages do not display the header but only the data. If we need to display the header on every page, we can set it The following statement:

table.HeaderRows = 1;//For example, if there are two rows of headers, you can set 2

3. PDF generation download

We can use the form of MemoryStream when creating a file, and then convert the MemoryStream file stream into base64 character encoding, and return it to the front end for direct download. See three for details.

4. Complete code:

using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Data;
using System.IO;
using System. Linq;

namespace SIE.Common.Helper.Tools
{<!-- -->
    public class ConvertPdf
    {<!-- -->

        public static float _fontSize= 12; //font size
        public static float _fontSize2 = 10;
        public static Rectangle _pageSize = PageSize.A4;//Set pdf document paper size
        //The font is read in Windows system Arial,
        public static BaseFont basefont = BaseFont.CreateFont(@"C:\Windows\Fonts\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

        /// <summary>
        /// DataTable exported to Excel's MemoryStream
        /// </summary>
        /// <param name="dtStru">Header</param>
        /// <param name="dtSource">data</param>
        /// <param name="title"></param>
        /// <returns></returns>
        public static string ExportPDF(DataTable dtStru, DataTable dtSource, string title)
        {<!-- -->
            MemoryStream mspdf = new MemoryStream();
            string base64Code = null;

            iTextSharp.text.Font font = new Font(basefont, _fontSize2, Font.BOLD);//Title
            iTextSharp.text.Font font2 = new Font(basefont, _fontSize2);//Common column

            Document document = new Document(_pageSize, 14, 14, 28, 24);
            PdfWriter pdfWriter= PdfWriter. GetInstance(document, mspdf);
            ItextPdfHeaderFooter headerFooter = new ItextPdfHeaderFooter();
            pdfWriter. PageEvent = headerFooter;

            document. Open();
            document. AddTitle(title);
            Paragraph element = new Paragraph(title, new Font(basefont, 14));
            element.SpacingAfter = 10; //Set the spacing from the content behind
            element.Alignment = Element.ALIGN_CENTER;
            document. Add(element);
            PdfPTable table = new PdfPTable(dtStru.Rows.Count);
            
            table.WidthPercentage = 100;//Set the table width percentage
            var width = (from dt in dtStru.AsEnumerable() select float.Parse(dt["width"].ToString())).ToArray();
            table. SetTotalWidth(width);
            #region header
            foreach (DataRow item in dtStru.Rows)
            {<!-- -->
                PdfPCell cell = new PdfPCell(new Paragraph(item["value"].ToString(), font));
                //cell.Colspan = 2; //Define the span of a table cell
                cell.Rowspan = 2;
                cell.BackgroundColor = new BaseColor(142,229,238);
                cell.VerticalAlignment = PdfPCell.ALIGN_MIDDLE; //vertically centered
                cell.HorizontalAlignment = PdfPCell.ALIGN_CENTER;//horizontal center
                table.AddCell(cell);
            }
            #endregion
            
            var i = 0;
            #region Data Loading
            foreach (DataRow item in dtSource.Rows)
            {<!-- -->
                i + + ;
                foreach (DataRow item2 in dtStru.Rows)
                {<!-- -->
                    
                    var fldname = item2["name"].ToString();
                    var df_value = item[fldname].ToString();
                    PdfPCell cell_data = new PdfPCell(new Paragraph(df_value, font2));
                    //interlaced color
                    if (i % 2 == 0)
                    {<!-- -->
                        cell_data.BackgroundColor = new BaseColor(253, 245, 230);
                    }
                
            cell_data.VerticalAlignment = PdfPCell.ALIGN_MIDDLE; //vertically centered
                    cell_data.HorizontalAlignment = PdfPCell.ALIGN_CENTER;//horizontal center
                    table.AddCell(cell_data);
                }
            }
            #endregion
            //Set the number of headers so that it can be displayed on every page
            if (dtSource. Rows. Count == 0)
            {<!-- -->
                table.HeaderRows = 1;
            }else
            {<!-- -->
                table.HeaderRows = 2;
            }
            document. Add(table);
            document. Close();
            //Convert base64 encoding
            base64Code = Convert.ToBase64String(mspdf.ToArray());
            return base64Code;
        }
    }
    /// <summary>
    /// Inherit PdfPageEventHelper, rewrite header and footer
    /// </summary>
    public class ItextPdfHeaderFooter : PdfPageEventHelper
    {<!-- -->
        PdfContentByte cb;
        PdfTemplate template;
        // Chinese font
        BaseFont bf = BaseFont.CreateFont(@"C:\Windows\Fonts\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        
        // Print Time
        DateTime PrintTime = DateTime. Now;
        float fontSize = 10; //font size
        float leftMargins = 14;//left margin
        float rightMargins = 14;//right margin
        float bottomMargins = 12;//bottom margin
        float topMargins = 12;//top margin

        #region header basic properties
        private string _Title;
        public string Title
        {<!-- -->
            get {<!-- --> return _Title; }
            set {<!-- --> _Title = value; }
        }
        public PdfPTable_Table;
        public PdfPTable Table
        {<!-- -->
            get {<!-- --> return _Table; }
            set {<!-- --> _Table=value; }
        }
        private string _HeaderLeft;
        public string HeaderLeft
        {<!-- -->
            get {<!-- --> return _HeaderLeft; }
            set {<!-- --> _HeaderLeft = value; }
        }
        private string _HeaderRight;
        public string HeaderRight
        {<!-- -->
            get {<!-- --> return _HeaderRight; }
            set {<!-- --> _HeaderRight = value; }
        }
        #endregion

        // Override the onOpenDocument method
        public override void OnOpenDocument(PdfWriter writer, Document document)
        {<!-- -->
            try
            {<!-- -->
                PrintTime = DateTime. Now;
                cb = writer. DirectContent;
                template = cb.CreateTemplate(50, 50);
            }
            catch (DocumentException de)
            {<!-- -->
            }
            catch (System.IO.IOException ioe)
            {<!-- -->
            }
        }
        /// <summary>
        /// Header--header
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="document"></param>
        public override void OnStartPage(PdfWriter writer, Document document)
        {<!-- -->
            base.OnStartPage(writer, document);
            Rectangle pageSize = document. PageSize;
            if (Title != null)
            {<!-- -->
                cb. BeginText();
                cb. SetFontAndSize(bf, fontSize);
                cb. SetRGBColorFill(50, 50, 200);
                cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetTop(topMargins));
                cb.ShowText(Title);
                cb. EndText();
            }
                iTextSharp.text.Font font = new Font(bf, 10, Font.NORMAL, new BaseColor(110, 84, 40));//title
                PdfPTable HeaderTable = new PdfPTable(2);
                HeaderTable.DefaultCell.VerticalAlignment = Element.ALIGN_MIDDLE;
                HeaderTable.TotalWidth = pageSize.Width - 28;
                HeaderTable.SetWidthPercentage(new float[] {<!-- --> 45, 45 }, pageSize);

                PdfPCell HeaderLeftCell = new PdfPCell(new Phrase(8, "xxxx company", font));
                HeaderLeftCell. BorderWidthLeft = 0;
                HeaderLeftCell.BorderWidthTop = 0;
                HeaderLeftCell. BorderWidthRight = 0;
                HeaderTable.AddCell(HeaderLeftCell);
                PdfPCell HeaderRightCell = new PdfPCell(new Phrase(8, "xxxx department", font));
                HeaderRightCell.HorizontalAlignment = PdfPCell.ALIGN_RIGHT;
                HeaderRightCell. BorderWidthLeft = 0;
            HeaderRightCell. BorderWidthRight = 0;
            HeaderRightCell.BorderWidthTop = 0;
            HeaderTable.AddCell(HeaderRightCell);
                cb. SetRGBColorFill(0, 0, 0);
                HeaderTable.WriteSelectedRows(0, -1, pageSize.GetLeft(14), pageSize.GetTop(8), cb);
        }
        /// <summary>
        /// Footer--page number
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="document"></param>
        public override void OnEndPage(PdfWriter writer, Document document)
        {<!-- -->
            base.OnEndPage(writer, document);
            int pageN = writer. PageNumber;
            String text = "第" + pageN + "page,";
            float len = bf. GetWidthPoint(text, fontSize);
            Rectangle pageSize = document. PageSize;
            cb.SetRGBColorFill(100, 100, 100);
            cb. BeginText();
            cb. SetFontAndSize(bf, fontSize);
            cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetBottom(bottomMargins));
            cb.ShowText(text);
            cb. EndText();
            cb.AddTemplate(template, pageSize.GetLeft(leftMargins) + len, pageSize.GetBottom(bottomMargins));

            cb. BeginText();
            cb. SetFontAndSize(bf, fontSize);
            cb.ShowTextAligned(PdfContentByte.ALIGN_RIGHT,
            "Generation time: " + PrintTime.ToString(),
            pageSize. GetRight(rightMargins),
            pageSize. GetBottom(bottomMargins), 0);
            cb. EndText();
        }
        public override void OnCloseDocument(PdfWriter writer, Document document)
        {<!-- -->
            base.OnCloseDocument(writer, document);
            template.BeginText();
            template. SetFontAndSize(bf, fontSize);
            template. SetTextMatrix(0, 0);
            template.ShowText("total" + (writer.PageNumber - 1) + "page");
            template. EndText();
        }
    }

}

3. Front-end JS download PDF file

Get the base64 string from the backend, convert it to Uint8Array type, then convert it to blob type, and finally download it.

1. JS function:

/*res returned string*/
function (res) {<!-- -->
                var base64 = JSON. parse(res. Result);
                base64 = base64.replace(/[\
\r]/g, '');
                var raw = window.atob(base64);
                let rawLength = raw. length;
                //Convert to Uint8Array type that pdf.js can directly parse
                let uInt8Array = new Uint8Array(rawLength);
                for (let i = 0; i < rawLength; + + i) {<!-- -->
                    uInt8Array[i] = raw. charCodeAt(i);
                }
                // convert character content to blob
                var blob = new Blob([uInt8Array], {<!-- --> type: 'application/pdf' });//Convert to pdf type
                // Create a hidden downloadable link
                var eleLink = document. createElement('a');
                eleLink.download = title + '.pdf';
                eleLink.style.display = 'none';
                eleLink.href = URL.createObjectURL(blob);
                // trigger click
                document.body.appendChild(eleLink);
                eleLink.click();
                // then remove
                document.body.removeChild(eleLink);
            }

2. Final effect:

ps: It’s not easy to create, please like it! ! !