在MVC Razor中使用iTextSharp将HTML转换为PDF

18

我正在尝试使用在MVC Razor中将HTML转换为PDF,但我尝试的所有方法都无效。有人知道如何完成这个任务吗?

9个回答

34
这里是使用Razor引擎实现此解决方案的方法,而不是使用奇怪的<itext..标记。这样,您可以使用标准的HTML输出来完全控制PDF演示。该项目包含示例解决方案和源代码,并提供了nuget安装说明。请访问:https://github.com/andyhutch77/MvcRazorToPdf
Install-Package MvcRazorToPdf

这也使用了新的itextsharp许可证,因此不会受到其他答案中提到的任何负面影响。


1
兄弟,你太棒了,谢谢。我能改变页面方向吗? - Edgar Froes
@EdgarSalazar 没问题。由于它使用了iTextXmlWorker,我认为您应该能够通过将div样式设置为横向比例来解决这个问题。 - hutchonoid
@sports 是的,这里有一个表格示例:https://github.com/andyhutch77/MvcRazorToPdf/blob/master/MvcRazorToPdfExample/Views/Pdf/Index.cshtml - hutchonoid
此 DLL 不支持特定于文化的字符。 - klm_

4
public virtual void printpdf(string html)    
{
     String htmlText = html.ToString();
     Document document = new Document();
     string filePath = HostingEnvironment.MapPath("~/Content/Pdf/");
     PdfWriter.GetInstance(document, new FileStream(filePath + "\\pdf-"+Filename+".pdf", FileMode.Create));

     document.Open();    
     iTextSharp.text.html.simpleparser.HTMLWorker hw = new iTextSharp.text.html.simpleparser.HTMLWorker(document);       
     hw.Parse(new StringReader(htmlText));    
     document.Close();    
}

只需将html字符串作为参数传递进去,该字符串是通过renderpartialview获取的,例如text = viewname....


4
你应该查看RazorPDF,它使用iText生成PDF,但采用更友好的方式。

3
嗨,Rosdi Kasim。显然最新的iTextSharp版本(5.4.4)与RazorPDF不兼容,导致其无法使用。 - real_yggdrasil
@real_yggdrasil 小心啊,最新的iTextSharp(从5.x开始)有不同的许可证。而且“无用”并不是很有帮助..尝试提交你的问题并附上一些示例或详细描述。 - Rosdi Kasim
1
我不同意。它已经变得无用了,因为它什么也做不了,并且自2012年以来没有更新过。 - Sinaesthetic

3

有一个详细的逐步教程在CodeProject网站上,你可以参考。它说明了如何使用iTextSharp将ASP.NET MVC的视图作为PDF文件提供,进行转换。但请注意,iTextSharp并不是用于将HTML转换为PDF的,因此对于复杂的HTML页面和CSS样式可能处理不太好。


1
我想知道,如果iTextSharp不是用于将HTML转换为PDF的话,那么有哪些免费源代码的替代品? - Dhwani
5
如果今天的日期大于2015年7月14日,请不要查看这个回答! - Nic
1
@MDDDC 为什么不呢?那我应该去哪里看呢? - Ariel Moraes
这个逐步教程不是“Razor”。它是aspx,Web Forms……它已经过时了。 - Mehmet Taha Meral

2

以下是使用evo html to pdf for .net将当前MVC视图转换为PDF并将结果PDF发送到浏览器以供下载的完整C# MVC Razor示例:

[HttpPost]
public ActionResult ConvertCurrentPageToPdf(FormCollection collection)
{
    object model = null;
    ViewDataDictionary viewData = new ViewDataDictionary(model);

    // The string writer where to render the HTML code of the view
    StringWriter stringWriter = new StringWriter();

    // Render the Index view in a HTML string
    ViewEngineResult viewResult = ViewEngines.Engines.FindView(ControllerContext, "Index", null);
    ViewContext viewContext = new ViewContext(
            ControllerContext,
            viewResult.View,
            viewData,
            new TempDataDictionary(),
            stringWriter
            );
    viewResult.View.Render(viewContext, stringWriter);

    // Get the view HTML string
    string htmlToConvert = stringWriter.ToString();

    // Get the base URL
    String currentPageUrl = this.ControllerContext.HttpContext.Request.Url.AbsoluteUri;
    String baseUrl = currentPageUrl.Substring(0, currentPageUrl.Length - "Convert_Current_Page/ConvertCurrentPageToPdf".Length);

    // Create a HTML to PDF converter object with default settings
    HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter();

    // Convert the HTML string to a PDF document in a memory buffer
    byte[] outPdfBuffer = htmlToPdfConverter.ConvertHtml(htmlToConvert, baseUrl);

    // Send the PDF file to browser
    FileResult fileResult = new FileContentResult(outPdfBuffer, "application/pdf");
    fileResult.FileDownloadName = "Convert_Current_Page.pdf";

    return fileResult;
}

2
将MVC HTML视图转换为PDF的好方法(即使与iTextSharp无关)是使用Rotativa:Rotativa
Install-Package Rotativa

这是基于wkhtmltopdf的,但比iTextSharp具有更好的CSS支持,并且非常容易与MVC集成,因为您可以将视图简单地作为PDF返回:

public ActionResult GetPdf()
{
    //...
    return new ViewAsPdf(model);// and you are done!
}

我曾经使用过Rotativa,它基于弹出窗口工作,需要解除弹出窗口拦截器的阻止。此外,在使用ViewAsPdf或ActionAsPdf之后,所有会话都将被清除。 - mahdi moghimi

0

如果您正在使用ASP.NET Core,而iTextSharp对您来说并不重要,那么这里是我的解决方案,使用PhantomJS:http://nikolay.it/Blog/2018/03/Generate-PDF-file-from-Razor-view-using-ASP-NET-Core-and-PhantomJS/37

从Razor视图获取HTML字符串

这一步非常简单。在ASP.NET Core中有一个名为IRazorViewEngine的服务,可以注入并用于获取视图。在提供了默认的ViewDataDictionaryActionContext之后,我们可以请求将视图呈现为StringWriter,然后将其轻松转换为字符串。以下是从给定的Razor视图文件获取字符串的可用代码:

public interface IViewRenderService
{
    Task<string> RenderToStringAsync(string viewName, object model);
}

public class ViewRenderService : IViewRenderService
{
    private readonly IRazorViewEngine razorViewEngine;
    private readonly ITempDataProvider tempDataProvider;
    private readonly IServiceProvider serviceProvider;

    public ViewRenderService(
        IRazorViewEngine razorViewEngine,
        ITempDataProvider tempDataProvider,
        IServiceProvider serviceProvider)
    {
        this.razorViewEngine = razorViewEngine;
        this.tempDataProvider = tempDataProvider;
        this.serviceProvider = serviceProvider;
    }

    public async Task<string> RenderToStringAsync(string viewName, object model)
    {
        var httpContext = new DefaultHttpContext { RequestServices = this.serviceProvider };
        var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

        using (var sw = new StringWriter())
        {
            var viewResult = this.razorViewEngine.GetView(null, viewName, false);

            if (viewResult.View == null)
            {
                throw new ArgumentNullException($"{viewName} does not match any available view");
            }

            var viewDictionary =
                new ViewDataDictionary(
                    new EmptyModelMetadataProvider(),
                    new ModelStateDictionary()) { Model = model };

            var viewContext = new ViewContext(
                actionContext,
                viewResult.View,
                viewDictionary,
                new TempDataDictionary(actionContext.HttpContext, this.tempDataProvider),
                sw,
                new HtmlHelperOptions());

            await viewResult.View.RenderAsync(viewContext);
            return sw.ToString();
        }
    }
}

这里有一件重要的事情:如果您使用视图编译(将视图预编译到YourProject.Web.PrecompiledViews.dll),那么使用GetView方法而不是FindView方法获取视图非常重要。更多信息在这里

使用PhantomJS从HTML生成PDF文件

为了完成此任务,我们将使用一个无头浏览器来呈现包含所有CSS和JS的HTML。有许多这样的工具,但我将使用PhantomJS(带JavaScript API的无头WebKit脚本)。 PhantomJS可以快速将呈现的页面保存为小型PDF。为了使PDF导出正常工作,我们需要一个.js文件,该文件将使用PhantomJS API告诉工具我们要导出文件:

"use strict";
var page = require('webpage').create(),
    system = require('system'),
    address,
    output;

console.log('Usage: rasterize.js [URL] [filename] [paperformat]');
address = system.args[1];
output = system.args[2];
page.viewportSize = { width: 600, height: 600 };
page.paperSize = { format: system.args[3], orientation: 'portrait', margin: '0.5cm' };

page.open(address, function (status) {
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit(1);
    } else {
        window.setTimeout(function () {
            page.render(output);
            phantom.exit();
        }, 200);
    }
});

下一步是运行phantomjs.exe进程并传递rasterize.js文件以及HTML文件和PDF结果输出文件名的路径。这在HtmlToPdfConverter.cs中完成:
public interface IHtmlToPdfConverter
{
    byte[] Convert(string htmlCode);
}

public class HtmlToPdfConverter : IHtmlToPdfConverter
{
    public byte[] Convert(string htmlCode)
    {
        var inputFileName = "input.html";
        var outputFileName = "output.pdf";
        File.WriteAllText(inputFileName, htmlCode);
        var startInfo = new ProcessStartInfo("phantomjs.exe")
                            {
                                WorkingDirectory = Environment.CurrentDirectory,
                                Arguments = string.Format(
                                    "rasterize.js \"{0}\" {1} \"A4\"",
                                    inputFileName,
                                    outputFileName),
                                UseShellExecute = true,
                            };

        var process = new Process { StartInfo = startInfo };
        process.Start();

        process.WaitForExit();

        var bytes = File.ReadAllBytes(outputFileName);

        File.Delete(inputFileName);
        File.Delete(outputFileName);

        return bytes;
    }
}

如果您要在Azure中部署应用程序,则将UseShellExecute设置为true非常重要。

一起使用代码

由于我们现在已经实现了IViewRenderServiceIHtmlToPdfConverter,因此我们可以通过首先在Startup.cs文件中注册它们(services.AddScoped<IViewRenderService, ViewRenderService>()services.AddScoped<IHtmlToPdfConverter, HtmlToPdfConverter>())来开始使用它们。现在让我们看看代码如何一起包装:

private readonly IViewRenderService viewRenderService;
private readonly IHtmlToPdfConverter htmlToPdfConverter;

public DashboardController(
    IViewRenderService viewRenderService,
    IHtmlToPdfConverter htmlToPdfConverter)
{
    this.viewRenderService = viewRenderService;
    this.htmlToPdfConverter = htmlToPdfConverter;
}

[HttpGet]
public async Task<IActionResult> GetPdf(SomeInputModel input)
{
    var model = this.GetViewModel(input);
    var htmlData = await this.viewRenderService.RenderToStringAsync("~/Views/Dashboard/GetPdf.cshtml", model);
    var fileContents = this.htmlToPdfConverter.Convert(htmlData);
    return this.File(fileContents, "application/pdf");
}

0

0

这是使用MVC的方法:

[Route("ABCDD")]
[HttpGet]
public void ABCDD() {
    WebClient wc = new WebClient();
    // string url = HttpContext.Current.Request.Url.AbsoluteUri;
    string url = "http://localhost:3042/Reports/COAListing";
    string fileContent = wc.DownloadString(url);

    List<string> tableContents = GetContents(fileContent, table_pattern);

    string HTMLString = String.Join(" ", tableContents.ToArray());

    Document pdfDoc = new Document(PageSize.A4, 10f, 10f, 10f, 0f);
    PdfWriter.GetInstance(pdfDoc, HttpContext.Current.Response.OutputStream);
    pdfDoc.Open();
    pdfDoc.Add(new Paragraph("Welcome to dotnetfox"));
    List<IElement> htmlarraylist = HTMLWorker.ParseToList(new StringReader(HTMLString), null);
    for (int k = 0; k < htmlarraylist.Count; k++) {
        pdfDoc.Add((IElement) htmlarraylist[k]);
    }

    pdfDoc.Close();
    HttpContext.Current.Response.ContentType = "pdf/application";
    HttpContext.Current.Response.AddHeader("content-disposition", "attachment;" +
            "filename=sample.pdf");
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    HttpContext.Current.Response.Write(pdfDoc);
    HttpContext.Current.Response.End();
}

你的答案使用了已经被弃用的 HTMLWorker,你应该使用 XMLWorker - Amedee Van Gasse
它给出错误:XMLWorker在当前上下文中不存在。 - Vivek Shukla
你使用的是哪个版本的iTextSharp?你能在iTextSharp 5.5.9中重现它吗? - Amedee Van Gasse
是的,它是 iTextSharp 5.5.9。 - Vivek Shukla
你能在iText 7.1.2 + pdfHTML中重现它吗? - Amedee Van Gasse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接