-->

调用wkhtmltopdf生成与HTML PDF(Calling wkhtmltopdf to ge

2019-06-21 02:27发布

我试图创建一个HTML文件,PDF文件。 环顾四周过了一会儿,我发现: wkhtmltopdf是完美的。 我需要调用从ASP.NET服务器这个.exe文件。 我已经尝试:

    Process p = new Process();
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.FileName = HttpContext.Current.Server.MapPath("wkhtmltopdf.exe");
    p.StartInfo.Arguments = "TestPDF.htm TestPDF.pdf";
    p.Start();
    p.WaitForExit();

由于没有任何文件的成功在服务器上创建的。 谁能给我一个正确的方向指针? 我把wkhtmltopdf.exe文件在网站的顶级目录。 还有其它地方,应该在哪里举行?


编辑:如果任何人有更好的解决方案,从HTML动态地创建PDF文件时,请让我知道。

Answer 1:

更新:
我的回答如下,在磁盘上创建PDF文件。 然后,我流的是文件到用户浏览器作为下载。 考虑使用像下面哈斯的回答有所收获wkhtml2pdf输出到流代替,然后发送直接向用户 - 这将绕过许多问题与文件权限等。

我原来的答复:
请确保您所指定的,通过IIS的服务器(通常NETWORK_SERVICE我认为)上运行ASP.NET进程是可写的PDF输出路径。

我的是这样(和它的作品):

/// <summary>
/// Convert Html page at a given URL to a PDF file using open-source tool wkhtml2pdf
/// </summary>
/// <param name="Url"></param>
/// <param name="outputFilename"></param>
/// <returns></returns>
public static bool HtmlToPdf(string Url, string outputFilename)
{
    // assemble destination PDF file name
    string filename = ConfigurationManager.AppSettings["ExportFilePath"] + "\\" + outputFilename + ".pdf";

    // get proj no for header
    Project project = new Project(int.Parse(outputFilename));

    var p = new System.Diagnostics.Process();
    p.StartInfo.FileName = ConfigurationManager.AppSettings["HtmlToPdfExePath"];

    string switches = "--print-media-type ";
    switches += "--margin-top 4mm --margin-bottom 4mm --margin-right 0mm --margin-left 0mm ";
    switches += "--page-size A4 ";
    switches += "--no-background ";
    switches += "--redirect-delay 100";

    p.StartInfo.Arguments = switches + " " + Url + " " + filename;

    p.StartInfo.UseShellExecute = false; // needs to be false in order to redirect output
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    p.StartInfo.RedirectStandardInput = true; // redirect all 3, as it should be all 3 or none
    p.StartInfo.WorkingDirectory = StripFilenameFromFullPath(p.StartInfo.FileName);

    p.Start();

    // read the output here...
    string output = p.StandardOutput.ReadToEnd(); 

    // ...then wait n milliseconds for exit (as after exit, it can't read the output)
    p.WaitForExit(60000); 

    // read the exit code, close process
    int returnCode = p.ExitCode;
    p.Close(); 

    // if 0 or 2, it worked (not sure about other values, I want a better way to confirm this)
    return (returnCode == 0 || returnCode == 2);
}


Answer 2:

我有同样的问题,当我试图使用MSMQ与Windows服务,但它是出于某种原因很慢。 (处理部分)。

这是最后的工作:

private void DoDownload()
{
    var url = Request.Url.GetLeftPart(UriPartial.Authority) + "/CPCDownload.aspx?IsPDF=False?UserID=" + this.CurrentUser.UserID.ToString();
    var file = WKHtmlToPdf(url);
    if (file != null)
    {
        Response.ContentType = "Application/pdf";
        Response.BinaryWrite(file);
        Response.End();
    }
}

public byte[] WKHtmlToPdf(string url)
{
    var fileName = " - ";
    var wkhtmlDir = "C:\\Program Files\\wkhtmltopdf\\";
    var wkhtml = "C:\\Program Files\\wkhtmltopdf\\wkhtmltopdf.exe";
    var p = new Process();

    p.StartInfo.CreateNoWindow = true;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    p.StartInfo.RedirectStandardInput = true;
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.FileName = wkhtml;
    p.StartInfo.WorkingDirectory = wkhtmlDir;

    string switches = "";
    switches += "--print-media-type ";
    switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm ";
    switches += "--page-size Letter ";
    p.StartInfo.Arguments = switches + " " + url + " " + fileName;
    p.Start();

    //read output
    byte[] buffer = new byte[32768];
    byte[] file;
    using(var ms = new MemoryStream())
    {
        while(true)
        {
            int read =  p.StandardOutput.BaseStream.Read(buffer, 0,buffer.Length);

            if(read <=0)
            {
                break;
            }
            ms.Write(buffer, 0, read);
        }
        file = ms.ToArray();
    }

    // wait or exit
    p.WaitForExit(60000);

    // read the exit code, close process
    int returnCode = p.ExitCode;
    p.Close();

    return returnCode == 0 ? file : null;
}

由于格雷厄姆Ambrose和其他人。



Answer 3:

好了,这是一个老问题,但一个优秀的一个。 而且,由于我没有找到一个很好的答案,我做我自己的:) 另外,我已经发布了这个超级简单的项目到GitHub上。

下面是一些示例代码:

var pdfData = HtmlToXConverter.ConvertToPdf("<h1>SOO COOL!</h1>");

这里有一些关键点:

  • 没有的P / Invoke
  • 一个新的进程无法创建
  • 没有文件系统(所有RAM)
  • 与智能感知等原生.NET的DLL
  • 能力生成PDF或PNG( HtmlToXConverter.ConvertToPng


Answer 4:

退房的C#包装库(使用P / Invoke)为wkhtmltopdf库: https://github.com/pruiz/WkHtmlToXSharp



Answer 5:

有许多原因,这通常是一个坏主意。 你将如何来控制得到催生关闭可执行文件,但最终在内存中流落如果有一个崩溃? 什么拒绝服务攻击,或者如果有什么恶意进入TestPDF.htm?

我的理解是,ASP.NET用户帐户不会有本地登录权限。 它也需要有正确的文件权限来访问可执行文件,并写入到文件系统。 您需要编辑本地安全策略,并让ASP.NET用户帐户(也许ASPNET)本地登录(也可能是在默认情况下,拒绝列表)。 然后,你需要编辑在NTFS文件系统中的其他文件的权限。 如果你是在一个共享的主机环境中可能无法申请你所需要的配置。

使用外部可执行这样,最好的办法是从ASP.NET代码排队工作,有某种服务的监控队列。 如果你这样做,你会保护自己免受各种不好的事情发生。 不断变化的用户帐户的维护问题,不值得在我看来的努力,并同时建立一个服务或计划作业是一种痛苦,它只是一个更好的设计。 在ASP.NET页面应该轮询输出结果队列,你可以用一个等待页面呈现给用户。 这是在大多数情况下可以接受的。



Answer 6:

你可以告诉wkhtmltopdf通过指定发送它的输出到SOUT“ - ”作为输出文件。 然后,您可以阅读的过程中输出到响应流,并避免与写入文件系统中的权限问题。



Answer 7:

谢谢你的问题/答案/所有的上述评论。 我来到这个当我在写我自己的C#包装为WKHTMLtoPDF并回答了几个,我有问题。 最后我在博客中写这一点 - 这也包括我的包装(毫无疑问你会看到上面的渗入我的代码中的条目“灵感” ......)

http://icanmakethiswork.blogspot.de/2012/04/making-pdfs-from-html-in-c-using.html

再次感谢你们!



Answer 8:

我拿到这个具有2018的东西。

我使用异步。 我流和从wkhtmltopdf。 我创建了一个新的StreamWriter因为wkhtmltopdf默认情况下,预计UTF-8,但过程开始时,它被设置为别的东西。

我不包括不少争论,因为那些从用户到不同用户。 您可以添加你需要使用additionalArgs什么。

我删除p.WaitForExit(...),因为我如果失败的话,它会反正挂在没有被处理await tStandardOutput 。 如果需要超时,那么你就必须调用Wait(...)上用的CancellationToken或超时的不同任务和相应的处理。

public async Task<byte[]> GeneratePdf(string html, string additionalArgs)
{
    ProcessStartInfo psi = new ProcessStartInfo
    {
        FileName = @"C:\Program Files\wkhtmltopdf\wkhtmltopdf.exe",
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        Arguments = "-q -n " + additionalArgs + " - -";
    };

    using (var p = Process.Start(psi))
    using (var pdfSream = new MemoryStream())
    using (var utf8Writer = new StreamWriter(p.StandardInput.BaseStream, 
                                             Encoding.UTF8))
    {
        await utf8Writer.WriteAsync(html);
        utf8Writer.Close();
        var tStdOut = p.StandardOutput.BaseStream.CopyToAsync(pdfSream);
        var tStdError = p.StandardError.ReadToEndAsync();

        await tStandardOutput;
        string errors = await tStandardError;

        if (!string.IsNullOrEmpty(errors)) { /* deal/log with errors */ }

        return pdfSream.ToArray();
    }
}

事情我还没有包括在里面,但可能是有用的,如果你有图片,CSS或wkhtmltopdf将呈现HTML页面时加载其他的东西:

  • 您可以使用--cookie通过身份验证cookie
  • 在HTML页面的标题,你可以用HREF指向基本标签设置为服务器和wkhtmltopdf将使用如果需要的话


Answer 9:

在ASP.NET的进程可能没有该目录的写入权限。

尝试告诉它写入到%TEMP%看看它是否工作。

同时,让你的ASP页面的.Net呼应进程的输出和错误,并检查错误消息。



Answer 10:

一般情况下返回代码=是否正确创建PDF文件和correctly.If它没有创造那么值在-ve范围0即将到来。



Answer 11:

using System;
using System.Diagnostics;
using System.Web;

public partial class pdftest : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    private void fn_test()
    {
        try
        {
            string url = HttpContext.Current.Request.Url.AbsoluteUri;
            Response.Write(url);
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = 
                @"C:\PROGRA~1\WKHTML~1\wkhtmltopdf.exe";//"wkhtmltopdf.exe";
            startInfo.Arguments = url + @" C:\test"
                 + Guid.NewGuid().ToString() + ".pdf";
            Process.Start(startInfo);
        }
        catch (Exception ex)
        {
            string xx = ex.Message.ToString();
            Response.Write("<br>" + xx);
        }
    }
    protected void btn_test_Click(object sender, EventArgs e)
    {
        fn_test();
    }
}


文章来源: Calling wkhtmltopdf to generate PDF from HTML