ASP.Net MVC - Perfect solution for HTML to PDF using ITextSharp (Chinese is also possible)

Keywords: encoding xml

Preface:

Recently, in a small project for writing experiment reports online that was handed over by a teacher, there was a need to convert the experiment reports submitted by students (in the form of HTML) directly into PDF for easy download and printing.

Previously, they were all implemented directly using rdlc reports, but this time they involve pictures, and more importantly, PDF formats must be the same as the HTML pages submitted by students.After consulting the materials on the Internet,

The ITextSharp plug-in was found.

ITextSharp is powerful, but when dealing with img tags in HMTL, src can only be absolute paths.(

Solutions I wrote in another article

Text:

ITextSharp is not covered much.Link to the project Download link is http://files.cnblogs.com/files/zuochengsi-9/H%E8%BD%ACPDF.zip

Add ITextSharp.dll and ITextSharp.xmlworker.dll before starting the project below. The latter is for Chinese use

References can be downloaded from NuGet, but the specific method is not described.There are many solutions online.

Project Structure Diagram:

Let's start with the main operations:

Step: 1. Convert a local view to a string.

2. Integrate strings into PDF documents and return byte arrays.

3. Speak bitstream is written to the binary stream of the HTTP content body.

 

View to String Code:

First, two new classes are created, and the main logic for string literals is in the RenderViewToString method.

public class HtmlViewRenderer
    {
        public string RenderViewToString(Controller controller, string viewName, object viewData)
        {
            var renderedView = new StringBuilder();
            using (var responseWriter = new StringWriter(renderedView))
            {
                var fakeResponse = new HttpResponse(responseWriter);
                var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
                var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), controller.ControllerContext.RouteData, controller.ControllerContext.Controller);

                var oldContext = HttpContext.Current;
                HttpContext.Current = fakeContext;

                using (var viewPage = new ViewPage())
                {
                    var html = new HtmlHelper(CreateViewContext(responseWriter, fakeControllerContext), viewPage);
                    html.RenderPartial(viewName,viewData);
                    HttpContext.Current = oldContext;
                }
            }

            return renderedView.ToString();
        }

        private static ViewContext CreateViewContext(TextWriter responseWriter, ControllerContext fakeControllerContext)
        {
            return new ViewContext(fakeControllerContext, new FakeView(), new ViewDataDictionary(), new TempDataDictionary(), responseWriter);
        }
    }
public class FakeView : IView
    {

        public void Render(ViewContext viewContext, TextWriter writer)
        {
            throw new NotImplementedException();
        }

    }

 

Create a new controller and call the RenderViewToString method you just wrote.(You will create a new HomeController later, inherit the PdfViewController, and call ViewPdf in the Action s of the HomeController)

public class PdfViewController : Controller
    {
        private readonly HtmlViewRenderer htmlViewRenderer;

        public PdfViewController()
        {
            this.htmlViewRenderer = new HtmlViewRenderer();
        }

        protected string ViewPdf(string viewName,object model)
        {
            // Render the view html to a string.
            string htmlText = this.htmlViewRenderer.RenderViewToString(this, viewName,model);
            return htmlText;
        }

    }

"String byte[]" (this method is placed in the HomeController written later)

public byte[] ConvertHtmlTextToPDF(string htmlText)
        {
            if (string.IsNullOrEmpty(htmlText))
            {
                return null;
            }
            //Avoid when htmlText Nothing html tag When plain text for labels, turn PDF Will hang, so always add<p>Label
            htmlText = "<p>" + htmlText + "</p>";

            MemoryStream outputStream = new MemoryStream();//To PDF To which stream
            byte[] data = Encoding.UTF8.GetBytes(htmlText);//String to byte[]
            MemoryStream msInput = new MemoryStream(data);
            Document doc = new Document();//To write PDF File, constructor sub-default straight A4
            PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);
            //Specifies that the file is preset to be archived with a zoom of 100%
            PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
            //Open Document file 
            doc.Open();
            //Use XMLWorkerHelper hold Html parse reach PDF File
            XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8, new UnicodeFontFactory());
            //Will pdfDest Set data written to PDF File
            PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);
            writer.SetOpenAction(action);
            doc.Close();
            msInput.Close();
            outputStream.Close();
            //Return PDF Archives 
            return outputStream.ToArray();

        }

XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8, new UnicodeFontFactory()); the "UnicodeFontFactory" class in this code encapsulates the Chinese font settings.The code is as follows:

 

public class UnicodeFontFactory : FontFactoryImp 
    {
        private static readonly string arialFontPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts),
            "arialuni.ttf");//arial unicode MS Is Complete unicode Font type.
        private static readonly string dfkai-sb Path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts),
          "KAIU.TTF");//dfkai-sb


        public override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color,
            bool cached)
        {
            //available Arial Or in typeface, choose one for yourself
            BaseFont baseFont = BaseFont.CreateFont(dfkai-sb Path, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            return new Font(baseFont, size, style, color);
        } 
    }

 

Create a new class to output the bitstream to response.OutputStream:

 

public class BinaryContentResult : ActionResult
    {
        private readonly string contentType;
        private readonly byte[] contentBytes;

        public BinaryContentResult(byte[] contentBytes, string contentType)
        {
            this.contentBytes = contentBytes;
            this.contentType = contentType;  
        }

        public override void ExecuteResult(ControllerContext context)
        {
            var response = context.HttpContext.Response;
            response.Clear();
            response.Cache.SetCacheability(HttpCacheability.Public);
            response.ContentType = this.contentType;
//The next paragraph plus is a download page
response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode("file name.pdf", System.Text.Encoding.UTF8));



using (var stream = new MemoryStream(this.contentBytes)) { stream.WriteTo(response.OutputStream); stream.Flush(); } } }

 

Now take a look at the HomeController

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Mvc;
using HTML turn PDF.Models;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.tool.xml;
using ReportManagement;

namespace HTML turn PDF.Controllers
{
    public class HomeController :PdfViewController
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }
        /// <summary>
        /// Execute this Url,Download PDF Archives
        /// </summary>
        /// <returns></returns>
        public ActionResult DownloadPdf()
        {
            var person = new People("Left into");
            string htmlText = this.ViewPdf("Preview",person);
            byte[] pdfFile = this.ConvertHtmlTextToPDF(htmlText);
            return new BinaryContentResult(pdfFile, "application/pdf");
        }
        /// <summary>
        /// Will Html Text output to PDF File
        /// </summary>
        /// <param name="htmlText"></param>
        /// <returns></returns>
        public byte[] ConvertHtmlTextToPDF(string htmlText)
        {
            if (string.IsNullOrEmpty(htmlText))
            {
                return null;
            }
            //Avoid when htmlText Nothing html tag When plain text for labels, turn PDF Will hang, so always add<p>Label
            htmlText = "<p>" + htmlText + "</p>";

            MemoryStream outputStream = new MemoryStream();//To PDF To which stream
            byte[] data = Encoding.UTF8.GetBytes(htmlText);//String to byte[]
            MemoryStream msInput = new MemoryStream(data);
            Document doc = new Document();//To write PDF File, constructor sub-default straight A4
            PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);
            //Specifies that the file is preset to be archived with a zoom of 100%
            PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
            //Open Document file 
            doc.Open();
            //Use XMLWorkerHelper hold Html parse reach PDF File
            XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8, new UnicodeFontFactory());
            //Will pdfDest Set data written to PDF File
            PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);
            writer.SetOpenAction(action);
            doc.Close();
            msInput.Close();
            outputStream.Close();
            //Return PDF Archives 
            return outputStream.ToArray();

        }
    }
}

Step 2's ConvertHtmlTextToPDF method puts me right here, regardless of the design principles.In the code above, "Preview" is a local view, preferably in the same area as the HomeController, otherwise you have to change the code for step one.

Finally, the code for my foreground section is very simple (Preview.cshtml).

@model HTML to PDF.Models.People
  <!--Here's the absolute path on my machine-->         
<img src="E:\12.bmp" width="64" height="64" /> 
<p>Hello, my name is @Model.Name</p>

  

Special note: Don't use ajax.ActionLink when jumping to the "DownloadPdf" Action we wrote.Otherwise, there would be random code and I couldn't find a solution.

Reference material: http://www.tuicool.com/articles/aUfqeu

       http://dwtedx.com/itshare_233.html

 

Reprinted from: http://www.cnblogs.com/zuochengsi-9/p/5483808.html

Posted by simun on Tue, 14 Apr 2020 21:17:55 -0700